1 16 package org.apache.commons.vfs.provider.webdav; 17 18 import org.apache.commons.httpclient.HttpException; 19 import org.apache.commons.httpclient.HttpStatus; 20 import org.apache.commons.httpclient.HttpURL; 21 import org.apache.commons.vfs.FileObject; 22 import org.apache.commons.vfs.FileSystemException; 23 import org.apache.commons.vfs.FileType; 24 import org.apache.commons.vfs.NameScope; 25 import org.apache.commons.vfs.RandomAccessContent; 26 import org.apache.commons.vfs.provider.AbstractFileObject; 27 import org.apache.commons.vfs.provider.AbstractRandomAccessContent; 28 import org.apache.commons.vfs.provider.GenericFileName; 29 import org.apache.commons.vfs.provider.URLFileName; 30 import org.apache.commons.vfs.util.MonitorOutputStream; 31 import org.apache.commons.vfs.util.RandomAccessMode; 32 import org.apache.webdav.lib.BaseProperty; 33 import org.apache.webdav.lib.WebdavResource; 34 import org.apache.webdav.lib.methods.DepthSupport; 35 import org.apache.webdav.lib.methods.OptionsMethod; 36 import org.apache.webdav.lib.methods.XMLResponseMethodBase; 37 import org.apache.webdav.lib.properties.ResourceTypeProperty; 38 39 import java.io.DataInputStream ; 40 import java.io.FilterInputStream ; 41 import java.io.IOException ; 42 import java.io.InputStream ; 43 import java.io.OutputStream ; 44 import java.net.HttpURLConnection ; 45 import java.util.ArrayList ; 46 import java.util.Enumeration ; 47 import java.util.HashMap ; 48 import java.util.List ; 49 import java.util.Map ; 50 import java.util.Set ; 51 import java.util.TreeSet ; 52 53 58 public class WebdavFileObject 59 extends AbstractFileObject 60 implements FileObject 61 { 62 private final WebDavFileSystem fileSystem; 63 private final String urlCharset; 64 private WebdavResource resource; 65 private boolean redirectionResolved = false; 66 private Set allowedMethods = null; 67 69 private static volatile int tmpFileCount = 0; 70 private static final Object tmpFileCountSync = new Object (); 71 72 protected WebdavFileObject(final GenericFileName name, 73 final WebDavFileSystem fileSystem) 74 { 75 super(name, fileSystem); 76 this.fileSystem = fileSystem; 77 this.urlCharset = WebdavFileSystemConfigBuilder.getInstance().getUrlCharset(getFileSystem().getFileSystemOptions()); 78 } 79 80 83 protected void doAttach() throws Exception 84 { 85 if (resource == null) 86 { 87 setDavResource(null); 88 } 89 } 90 91 protected void doDetach() throws Exception 92 { 93 if (resource != null) 94 { 95 redirectionResolved = false; 97 allowedMethods = null; 98 99 resource.close(); 100 resource = null; 101 } 102 } 103 104 110 private void setDavResource(WebdavResource resource) throws Exception 111 { 112 redirectionResolved = false; 113 114 final URLFileName name = (URLFileName) getName(); 115 116 if (resource == null) 117 { 118 String pathEncoded = name.getPathQueryEncoded(urlCharset); 120 HttpURL url = new HttpURL(name.getUserName(), name.getPassword(), name.getHostName(), name.getPort()); 121 url.setEscapedPath(pathEncoded); 122 resource = new WebdavResource(fileSystem.getClient()) 123 { 124 }; 125 resource.setHttpURL(url, WebdavResource.NOACTION, 1); 126 } 127 128 this.resource = resource; 129 130 { 132 133 String pathEncoded = name.getPathQueryEncoded(urlCharset); 134 final OptionsMethod optionsMethod = new OptionsMethod(pathEncoded); 135 try 136 { 137 optionsMethod.setFollowRedirects(true); 138 final int status = fileSystem.getClient().executeMethod(optionsMethod); 139 if (status < 200 || status > 299) 140 { 141 if (status == 401 || status == 403) 142 { 143 setAllowedMethods(null); 144 145 processParentDavResource(); 147 return; 148 } 149 else 150 { 151 injectType(FileType.IMAGINARY); 152 } 153 return; 154 } 155 redirectionResolved = true; 157 resource.getHttpURL().setEscapedPath(optionsMethod.getURI().getPath()); 158 159 setAllowedMethods(optionsMethod.getAllowedMethods()); 160 boolean exists = false; 161 for (Enumeration enumeration = optionsMethod.getAllowedMethods(); enumeration.hasMoreElements();) 162 { 163 final String method = (String ) enumeration.nextElement(); 164 if (method.equals("COPY")) 167 { 168 exists = true; 169 break; 170 } 171 } 172 if (!exists) 173 { 174 injectType(FileType.IMAGINARY); 175 return; 176 } 177 178 try 179 { 180 resource.setProperties(WebdavResource.DEFAULT, 1); 181 } 182 catch (IOException e) 183 { 184 throw new FileSystemException(e); 185 } 186 } 187 finally 188 { 189 optionsMethod.releaseConnection(); 190 } 191 } 192 193 ResourceTypeProperty resourceType = resource.getResourceType(); 194 if (resourceType.isCollection()) 195 { 196 injectType(FileType.FOLDER); 197 } 198 else 199 { 200 injectType(FileType.FILE); 201 } 202 } 203 204 private void setAllowedMethods(Enumeration allowedMethods) 205 { 206 this.allowedMethods = new TreeSet (); 207 208 if (allowedMethods == null) 209 { 210 return; 211 } 212 213 while (allowedMethods.hasMoreElements()) 214 { 215 this.allowedMethods.add(allowedMethods.nextElement()); 216 } 217 } 218 219 private boolean hasAllowedMethods(String method) throws IOException 220 { 221 if (allowedMethods == null) 222 { 223 getAllowedMethods(); 224 } 225 226 return allowedMethods.contains(method); 227 } 228 229 private void resolveRedirection() throws IOException , FileSystemException 230 { 231 if (redirectionResolved) 232 { 233 return; 234 } 235 236 final OptionsMethod optionsMethod = new OptionsMethod(getName().getPath()); 237 try 238 { 239 optionsMethod.setFollowRedirects(true); 240 final int status = fileSystem.getClient().executeMethod(optionsMethod); 241 if (status >= 200 && status <= 299) 242 { 243 setAllowedMethods(optionsMethod.getAllowedMethods()); 244 resource.getHttpURL().setEscapedPath(optionsMethod.getPath()); 245 redirectionResolved = true; 246 } 247 } 248 finally 249 { 250 optionsMethod.releaseConnection(); 251 } 252 } 253 254 private void processParentDavResource() throws FileSystemException 255 { 256 WebdavFileObject parent = (WebdavFileObject) getParent(); 257 try 258 { 259 parent.doListChildrenResolved(); 261 } 262 catch (Exception e) 263 { 264 throw new FileSystemException(e); 265 } 266 } 267 268 272 protected FileType doGetType() throws Exception 273 { 274 throw new IllegalStateException ("this should not happen"); 276 } 277 278 281 protected String [] doListChildren() throws Exception 282 { 283 return null; 285 } 286 287 290 protected FileObject[] doListChildrenResolved() throws Exception 291 { 292 doAttach(); 293 294 WebdavResource[] children = new org.apache.webdav.lib.WebdavResource[0]; 295 try 296 { 297 children = resource.listWebdavResources(); 298 } 299 catch (HttpException e) 300 { 301 if (e.getReasonCode() == HttpStatus.SC_MOVED_PERMANENTLY || e.getReasonCode() == HttpStatus.SC_MOVED_TEMPORARILY) 302 { 303 resolveRedirection(); 304 children = resource.listWebdavResources(); 305 } 306 else 307 { 308 throw e; 309 } 310 } 311 312 if (children == null) 313 { 314 throw new FileSystemException("vfs.provider.webdav/list-children.error", resource.getStatusMessage()); 315 } 316 317 List vfs = new ArrayList (children.length); 318 for (int i = 0; i < children.length; i++) 320 { 321 WebdavResource dav = children[i]; 322 323 String davName = dav.getHttpURL().getEscapedName(); 324 if ("".equals(davName)) 325 { 326 continue; 328 } 329 330 WebdavFileObject fo = (WebdavFileObject) getFileSystem().resolveFile( 331 getFileSystem().getFileSystemManager().resolveName( 332 getName(), 333 davName, 334 NameScope.CHILD)); 335 fo.setDavResource(dav); 336 337 vfs.add(fo); 339 } 340 341 return (WebdavFileObject[]) vfs.toArray(new WebdavFileObject[vfs.size()]); 342 } 344 345 348 protected void doCreateFolder() throws Exception 349 { 350 resource.getHttpURL().setPath(getName().getPathDecoded() + '/'); 353 final boolean ok = resource.mkcolMethod(); 354 if (!ok) 355 { 356 throw new FileSystemException("vfs.provider.webdav/create-collection.error", resource.getStatusMessage()); 357 } 358 359 reattach(); 361 } 362 363 366 protected void doDelete() throws Exception 367 { 368 resolveRedirection(); 369 final boolean ok = resource.deleteMethod(); 371 if (!ok) 372 { 373 throw new FileSystemException("vfs.provider.webdav/delete-file.error", resource.getStatusMessage()); 374 } 375 376 reattach(); 378 } 379 380 383 protected void doRename(FileObject newfile) throws Exception 384 { 385 389 final boolean ok = resource.moveMethod(newfile.getName().getPath()); 390 if (!ok) 391 { 392 throw new FileSystemException("vfs.provider.webdav/rename-file.error", resource.getStatusMessage()); 393 } 394 395 reattach(); 397 } 398 399 402 protected InputStream doGetInputStream() throws Exception 403 { 404 return resource.getMethodData(); 405 } 406 407 410 protected OutputStream doGetOutputStream(boolean bAppend) throws Exception 411 { 412 int fileCount; 413 FileObject webdavTmp; 414 synchronized (tmpFileCountSync) 415 { 416 tmpFileCount++; 417 fileCount = tmpFileCount; 418 } 419 webdavTmp = getFileSystem().getFileSystemManager().resolveFile("tmp://webdav_tmp.c" + fileCount); 420 return new WebdavOutputStream(webdavTmp); 421 } 422 423 426 protected long doGetContentSize() throws Exception 427 { 428 return resource.getGetContentLength(); 429 } 430 431 436 private class WebdavOutputStream 437 extends MonitorOutputStream 438 { 439 private final FileObject webdavTmp; 440 441 public WebdavOutputStream(FileObject webdavTmp) throws FileSystemException 442 { 443 super(webdavTmp.getContent().getOutputStream()); 444 this.webdavTmp = webdavTmp; 445 } 446 447 450 protected void onClose() throws IOException 451 { 452 454 resource.getHttpURL().setPath(getName().getPathDecoded()); 456 try 458 { 459 final boolean ok = resource.putMethod(webdavTmp.getContent().getInputStream()); 460 if (!ok) 461 { 462 throw new FileSystemException("vfs.provider.webdav/write-file.error", resource.getStatusMessage()); 463 } 464 } 465 finally 466 { 467 webdavTmp.close(); 469 webdavTmp.delete(); 470 } 471 } 472 } 473 474 protected void handleCreate(final FileType newType) throws Exception 475 { 476 reattach(); 479 super.handleCreate(newType); 480 } 481 482 487 private void reattach() throws FileSystemException 488 { 489 try 490 { 491 doDetach(); 492 doAttach(); 493 } 494 catch (Exception e) 495 { 496 throw new FileSystemException(e); 497 } 498 } 499 500 504 protected long doGetLastModifiedTime() throws Exception 505 { 506 return resource.getGetLastModified(); 507 } 508 509 512 protected Map doGetAttributes() throws Exception 513 { 514 final Map attributes = new HashMap (); 515 final Enumeration e = resource.propfindMethod(DepthSupport.DEPTH_0); 516 while (e.hasMoreElements()) 517 { 518 final XMLResponseMethodBase.Response response = (XMLResponseMethodBase.Response) e.nextElement(); 519 final Enumeration properties = response.getProperties(); 520 while (properties.hasMoreElements()) 521 { 522 final BaseProperty property = (BaseProperty) properties.nextElement(); 523 attributes.put(property.getLocalName(), property.getPropertyAsString()); 524 } 525 } 526 527 return attributes; 528 } 529 530 protected boolean doIsReadable() throws Exception 531 { 532 return hasAllowedMethods("GET"); 533 } 534 535 protected boolean doIsWriteable() throws Exception 536 { 537 return hasAllowedMethods("DELETE"); 540 } 541 542 private void getAllowedMethods() throws IOException 543 { 544 if (allowedMethods != null) 545 { 546 return; 547 } 548 549 final OptionsMethod optionsMethod = new OptionsMethod(getName().getPath()); 550 try 551 { 552 optionsMethod.setFollowRedirects(true); 553 final int status = fileSystem.getClient().executeMethod(optionsMethod); 554 if (status < 200 || status > 299) 555 { 556 if (status == 401 || status == 403) 557 { 558 setAllowedMethods(null); 559 return; 560 } 561 } 562 563 setAllowedMethods(optionsMethod.getAllowedMethods()); 564 } 565 finally 566 { 567 optionsMethod.releaseConnection(); 568 } 569 570 return; 571 } 572 573 protected RandomAccessContent doGetRandomAccessContent(final RandomAccessMode mode) throws Exception 574 { 575 return new WebdavRandomAccesContent(this, mode); 576 } 577 578 public static class WebdavRandomAccesContent extends AbstractRandomAccessContent 579 { 580 private final WebdavFileObject fileObject; 581 582 protected long filePointer = 0; 583 584 private DataInputStream dis = null; 585 586 private InputStream mis = null; 587 588 protected WebdavRandomAccesContent(final WebdavFileObject fileObject, final RandomAccessMode mode) 589 { 590 super(mode); 591 592 this.fileObject = fileObject; 593 } 594 595 public long getFilePointer() throws IOException 596 { 597 return filePointer; 598 } 599 600 public void seek(long pos) throws IOException 601 { 602 if (pos == filePointer) 603 { 604 return; 606 } 607 608 if (pos < 0) 609 { 610 throw new FileSystemException( 611 "vfs.provider/random-access-invalid-position.error", 612 new Object []{new Long (pos)}); 613 } 614 if (dis != null) 615 { 616 close(); 617 } 618 619 filePointer = pos; 620 } 621 622 private void createStream() throws IOException 623 { 624 if (dis != null) 625 { 626 return; 627 } 628 629 fileObject.resource.addRequestHeader("Range", "bytes=" 630 + filePointer + "-"); 631 final InputStream data = fileObject.resource.getMethodData(); 632 final int status = fileObject.resource.getStatusCode(); 633 634 if (status != HttpURLConnection.HTTP_PARTIAL) 635 { 636 data.close(); 637 throw new FileSystemException( 638 "vfs.provider.http/get-range.error", new Object []{ 639 fileObject.getName(), new Long (filePointer)}); 640 } 641 642 mis = data; 643 dis = new DataInputStream (new FilterInputStream (mis) 644 { 645 public int read() throws IOException 646 { 647 int ret = super.read(); 648 if (ret > -1) 649 { 650 filePointer++; 651 } 652 return ret; 653 } 654 655 public int read(byte b[]) throws IOException 656 { 657 int ret = super.read(b); 658 if (ret > -1) 659 { 660 filePointer += ret; 661 } 662 return ret; 663 } 664 665 public int read(byte b[], int off, int len) throws IOException 666 { 667 int ret = super.read(b, off, len); 668 if (ret > -1) 669 { 670 filePointer += ret; 671 } 672 return ret; 673 } 674 }); 675 } 676 677 public void close() throws IOException 678 { 679 if (dis != null) 680 { 681 dis.close(); 682 dis = null; 683 mis = null; 684 } 685 } 686 687 public long length() throws IOException 688 { 689 return fileObject.getContent().getSize(); 690 } 691 692 public byte readByte() throws IOException 693 { 694 createStream(); 695 byte data = dis.readByte(); 696 return data; 697 } 698 699 public char readChar() throws IOException 700 { 701 createStream(); 702 char data = dis.readChar(); 703 return data; 704 } 705 706 public double readDouble() throws IOException 707 { 708 createStream(); 709 double data = dis.readDouble(); 710 return data; 711 } 712 713 public float readFloat() throws IOException 714 { 715 createStream(); 716 float data = dis.readFloat(); 717 return data; 718 } 719 720 public int readInt() throws IOException 721 { 722 createStream(); 723 int data = dis.readInt(); 724 return data; 725 } 726 727 public int readUnsignedByte() throws IOException 728 { 729 createStream(); 730 int data = dis.readUnsignedByte(); 731 return data; 732 } 733 734 public int readUnsignedShort() throws IOException 735 { 736 createStream(); 737 int data = dis.readUnsignedShort(); 738 return data; 739 } 740 741 public long readLong() throws IOException 742 { 743 createStream(); 744 long data = dis.readLong(); 745 return data; 746 } 747 748 public short readShort() throws IOException 749 { 750 createStream(); 751 short data = dis.readShort(); 752 return data; 753 } 754 755 public boolean readBoolean() throws IOException 756 { 757 createStream(); 758 boolean data = dis.readBoolean(); 759 return data; 760 } 761 762 public int skipBytes(int n) throws IOException 763 { 764 createStream(); 765 int data = dis.skipBytes(n); 766 return data; 767 } 768 769 public void readFully(byte b[]) throws IOException 770 { 771 createStream(); 772 dis.readFully(b); 773 } 774 775 public void readFully(byte b[], int off, int len) throws IOException 776 { 777 createStream(); 778 dis.readFully(b, off, len); 779 } 780 781 public String readUTF() throws IOException 782 { 783 createStream(); 784 String data = dis.readUTF(); 785 return data; 786 } 787 788 public InputStream getInputStream() throws IOException 789 { 790 createStream(); 791 return dis; 792 } 793 } 794 795 } | Popular Tags |