1 16 package org.apache.commons.vfs.provider.ftp; 17 18 import org.apache.commons.logging.Log; 19 import org.apache.commons.logging.LogFactory; 20 import org.apache.commons.net.ftp.FTPFile; 21 import org.apache.commons.vfs.FileName; 22 import org.apache.commons.vfs.FileObject; 23 import org.apache.commons.vfs.FileSystemException; 24 import org.apache.commons.vfs.FileType; 25 import org.apache.commons.vfs.RandomAccessContent; 26 import org.apache.commons.vfs.provider.AbstractFileObject; 27 import org.apache.commons.vfs.provider.UriParser; 28 import org.apache.commons.vfs.util.Messages; 29 import org.apache.commons.vfs.util.MonitorInputStream; 30 import org.apache.commons.vfs.util.MonitorOutputStream; 31 import org.apache.commons.vfs.util.RandomAccessMode; 32 33 import java.io.IOException ; 34 import java.io.InputStream ; 35 import java.io.OutputStream ; 36 import java.util.Calendar ; 37 import java.util.Collections ; 38 import java.util.Iterator ; 39 import java.util.Map ; 40 import java.util.TreeMap ; 41 42 47 public class FtpFileObject 48 extends AbstractFileObject 49 { 50 private Log log = LogFactory.getLog(FtpFileObject.class); 51 52 private static final Map EMPTY_FTP_FILE_MAP = Collections.unmodifiableMap(new TreeMap ()); 53 54 private final FtpFileSystem ftpFs; 55 private final String relPath; 56 57 private FTPFile fileInfo; 59 private Map children; 60 private FileObject linkDestination; 61 62 protected FtpFileObject(final FileName name, 63 final FtpFileSystem fileSystem, 64 final FileName rootName) 65 throws FileSystemException 66 { 67 super(name, fileSystem); 68 ftpFs = fileSystem; 69 String relPath = UriParser.decode(rootName.getRelativeName(name)); 70 if (".".equals(relPath)) 71 { 72 this.relPath = null; 77 } 78 else 79 { 80 this.relPath = relPath; 81 } 82 } 83 84 90 private FTPFile getChildFile(final String name, final boolean flush) throws IOException 91 { 92 if (flush) 93 { 94 children = null; 95 } 96 97 doGetChildren(); 99 100 FTPFile ftpFile = (FTPFile) children.get(name); 102 return ftpFile; 103 } 104 105 108 private void doGetChildren() throws IOException 109 { 110 if (children != null) 111 { 112 return; 113 } 114 115 final FtpClient client = ftpFs.getClient(); 116 try 117 { 118 String key = FtpFileSystemConfigBuilder.getInstance().getEntryParser(getFileSystem().getFileSystemOptions()); 119 final FTPFile[] tmpChildren = client.listFiles(key, relPath); 120 if (tmpChildren == null || tmpChildren.length == 0) 121 { 122 children = EMPTY_FTP_FILE_MAP; 123 } 124 else 125 { 126 children = new TreeMap (); 127 128 for (int i = 0; i < tmpChildren.length; i++) 130 { 131 final FTPFile child = tmpChildren[i]; 132 if (child == null) 133 { 134 if (log.isDebugEnabled()) 135 { 136 log.debug(Messages.getString("vfs.provider.ftp/invalid-directory-entry.debug", 137 new Object [] 138 { 139 new Integer (i), relPath 140 })); 141 } 142 continue; 143 } 144 if (!".".equals(child.getName()) 145 && !"..".equals(child.getName())) 146 { 147 children.put(child.getName(), child); 148 } 149 } 150 } 151 } 152 finally 153 { 154 ftpFs.putClient(client); 155 } 156 } 157 158 161 protected void doAttach() 162 throws IOException 163 { 164 getInfo(false); 166 } 167 168 171 private void getInfo(boolean flush) throws IOException 172 { 173 final FtpFileObject parent = (FtpFileObject) getParent(); 174 FTPFile newFileInfo; 175 if (parent != null) 176 { 177 newFileInfo = parent.getChildFile(UriParser.decode(getName().getBaseName()), flush); 178 } 179 else 180 { 181 newFileInfo = new FTPFile(); 183 newFileInfo.setType(FTPFile.DIRECTORY_TYPE); 184 } 185 186 this.fileInfo = newFileInfo; 187 } 188 189 192 protected void doDetach() 193 { 194 this.fileInfo = null; 195 children = null; 196 } 197 198 201 protected void onChildrenChanged(FileName child, FileType newType) 202 { 203 if (children != null && newType.equals(FileType.IMAGINARY)) 204 { 205 try 206 { 207 children.remove(UriParser.decode(child.getBaseName())); 208 } 209 catch (FileSystemException e) 210 { 211 throw new RuntimeException (e.getMessage()); 212 } 213 } 214 else 215 { 216 children = null; 219 } 220 } 221 222 225 protected void onChange() throws IOException 226 { 227 children = null; 228 229 if (getType().equals(FileType.IMAGINARY)) 230 { 231 this.fileInfo = null; 233 return; 234 } 235 236 getInfo(true); 237 } 238 239 243 protected FileType doGetType() 244 throws Exception 245 { 246 if (this.fileInfo == null) 247 { 248 return FileType.IMAGINARY; 249 } 250 else if (this.fileInfo.isDirectory()) 251 { 252 return FileType.FOLDER; 253 } 254 else if (this.fileInfo.isFile()) 255 { 256 return FileType.FILE; 257 } 258 else if (this.fileInfo.isSymbolicLink()) 259 { 260 return getLinkDestination().getType(); 261 } 262 263 throw new FileSystemException("vfs.provider.ftp/get-type.error", getName()); 264 } 265 266 private FileObject getLinkDestination() throws FileSystemException 267 { 268 if (linkDestination == null) 269 { 270 final String path = this.fileInfo.getLink(); 271 FileName relativeTo = getName().getParent(); 272 if (relativeTo == null) 273 { 274 relativeTo = getName(); 275 } 276 FileName linkDestinationName = getFileSystem().getFileSystemManager().resolveName(relativeTo, path); 277 linkDestination = getFileSystem().resolveFile(linkDestinationName); 278 } 279 280 return linkDestination; 281 } 282 283 protected FileObject[] doListChildrenResolved() throws Exception 284 { 285 if (this.fileInfo.isSymbolicLink()) 286 { 287 return getLinkDestination().getChildren(); 288 } 289 290 return null; 291 } 292 293 296 protected String [] doListChildren() 297 throws Exception 298 { 299 doGetChildren(); 301 302 final String [] childNames = new String [children.size()]; 304 int childNum = -1; 305 Iterator iterChildren = children.values().iterator(); 306 while (iterChildren.hasNext()) 307 { 308 childNum++; 309 final FTPFile child = (FTPFile) iterChildren.next(); 310 childNames[childNum] = child.getName(); 311 } 312 313 return UriParser.encode(childNames); 314 } 315 316 319 protected void doDelete() throws Exception 320 { 321 final boolean ok; 322 final FtpClient ftpClient = ftpFs.getClient(); 323 try 324 { 325 if (this.fileInfo.isDirectory()) 326 { 327 ok = ftpClient.removeDirectory(relPath); 328 } 329 else 330 { 331 ok = ftpClient.deleteFile(relPath); 332 } 333 } 334 finally 335 { 336 ftpFs.putClient(ftpClient); 337 } 338 339 if (!ok) 340 { 341 throw new FileSystemException("vfs.provider.ftp/delete-file.error", getName()); 342 } 343 this.fileInfo = null; 344 children = EMPTY_FTP_FILE_MAP; 345 } 346 347 350 protected void doRename(FileObject newfile) throws Exception 351 { 352 final boolean ok; 353 final FtpClient ftpClient = ftpFs.getClient(); 354 try 355 { 356 String oldName = getName().getPath(); 357 String newName = newfile.getName().getPath(); 358 ok = ftpClient.rename(oldName, newName); 359 } 360 finally 361 { 362 ftpFs.putClient(ftpClient); 363 } 364 365 if (!ok) 366 { 367 throw new FileSystemException("vfs.provider.ftp/rename-file.error", new Object []{getName().toString(), newfile}); 368 } 369 this.fileInfo = null; 370 children = EMPTY_FTP_FILE_MAP; 371 } 372 373 376 protected void doCreateFolder() 377 throws Exception 378 { 379 final boolean ok; 380 final FtpClient client = ftpFs.getClient(); 381 try 382 { 383 ok = client.makeDirectory(relPath); 384 } 385 finally 386 { 387 ftpFs.putClient(client); 388 } 389 390 if (!ok) 391 { 392 throw new FileSystemException("vfs.provider.ftp/create-folder.error", getName()); 393 } 394 } 395 396 399 protected long doGetContentSize() throws Exception 400 { 401 if (this.fileInfo.isSymbolicLink()) 402 { 403 return getLinkDestination().getContent().getSize(); 404 } 405 else 406 { 407 return this.fileInfo.getSize(); 408 } 409 } 410 411 416 protected long doGetLastModifiedTime() throws Exception 417 { 418 if (this.fileInfo.isSymbolicLink()) 419 { 420 return getLinkDestination().getContent().getLastModifiedTime(); 421 } 422 else 423 { 424 Calendar timestamp = this.fileInfo.getTimestamp(); 425 if (timestamp == null) 426 { 427 return 0L; 428 } 429 else 430 { 431 return (timestamp.getTime().getTime()); 432 } 433 } 434 } 435 436 439 protected InputStream doGetInputStream() throws Exception 440 { 441 final FtpClient client = ftpFs.getClient(); 442 final InputStream instr = client.retrieveFileStream(relPath); 443 return new FtpInputStream(client, instr); 444 } 445 446 protected RandomAccessContent doGetRandomAccessContent(final RandomAccessMode mode) throws Exception 447 { 448 return new FtpRandomAccessContent(this, mode); 449 } 450 451 454 protected OutputStream doGetOutputStream(boolean bAppend) 455 throws Exception 456 { 457 final FtpClient client = ftpFs.getClient(); 458 OutputStream out = null; 459 if (bAppend) 460 { 461 out = client.appendFileStream(relPath); 462 } 463 else 464 { 465 out = client.storeFileStream(relPath); 466 } 467 468 if (out == null) 469 { 470 throw new FileSystemException("vfs.provider.ftp/output-error.debug", new Object [] 471 { 472 this.getName(), 473 client.getReplyString() 474 }); 475 } 476 477 return new FtpOutputStream(client, out); 478 } 479 480 String getRelPath() 481 { 482 return relPath; 483 } 484 485 FtpInputStream getInputStream(long filePointer) throws IOException 486 { 487 final FtpClient client = ftpFs.getClient(); 488 final InputStream instr = client.retrieveFileStream(relPath, filePointer); 489 if (instr == null) 490 { 491 throw new FileSystemException("vfs.provider.ftp/input-error.debug", new Object [] 492 { 493 this.getName(), 494 client.getReplyString() 495 }); 496 } 497 return new FtpInputStream(client, instr); 498 } 499 500 503 class FtpInputStream 504 extends MonitorInputStream 505 { 506 private final FtpClient client; 507 508 public FtpInputStream(final FtpClient client, final InputStream in) 509 { 510 super(in); 511 this.client = client; 512 } 513 514 void abort() throws IOException 515 { 516 client.abort(); 517 close(); 518 } 519 520 523 protected void onClose() throws IOException 524 { 525 final boolean ok; 526 try 527 { 528 ok = client.completePendingCommand(); 529 } 530 finally 531 { 532 ftpFs.putClient(client); 533 } 534 535 if (!ok) 536 { 537 throw new FileSystemException("vfs.provider.ftp/finish-get.error", getName()); 538 } 539 } 540 } 541 542 545 private class FtpOutputStream 546 extends MonitorOutputStream 547 { 548 private final FtpClient client; 549 550 public FtpOutputStream(final FtpClient client, final OutputStream outstr) 551 { 552 super(outstr); 553 this.client = client; 554 } 555 556 559 protected void onClose() throws IOException 560 { 561 final boolean ok; 562 try 563 { 564 ok = client.completePendingCommand(); 565 } 566 finally 567 { 568 ftpFs.putClient(client); 569 } 570 571 if (!ok) 572 { 573 throw new FileSystemException("vfs.provider.ftp/finish-put.error", getName()); 574 } 575 } 576 } 577 } 578 | Popular Tags |