KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > commons > vfs > provider > webdav > WebdavFileObject


1 /*
2  * Copyright 2002-2005 The Apache Software Foundation.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */

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 JavaDoc;
40 import java.io.FilterInputStream JavaDoc;
41 import java.io.IOException JavaDoc;
42 import java.io.InputStream JavaDoc;
43 import java.io.OutputStream JavaDoc;
44 import java.net.HttpURLConnection JavaDoc;
45 import java.util.ArrayList JavaDoc;
46 import java.util.Enumeration JavaDoc;
47 import java.util.HashMap JavaDoc;
48 import java.util.List JavaDoc;
49 import java.util.Map JavaDoc;
50 import java.util.Set JavaDoc;
51 import java.util.TreeSet JavaDoc;
52
53 /**
54  * A WebDAV file.
55  *
56  * @author <a HREF="mailto:adammurdoch@apache.org">Adam Murdoch</a>
57  */

58 public class WebdavFileObject
59     extends AbstractFileObject
60     implements FileObject
61 {
62     private final WebDavFileSystem fileSystem;
63     private final String JavaDoc urlCharset;
64     private WebdavResource resource;
65     private boolean redirectionResolved = false;
66     private Set JavaDoc allowedMethods = null;
67     // private HttpURL url;
68

69     private static volatile int tmpFileCount = 0;
70     private static final Object JavaDoc tmpFileCountSync = new Object JavaDoc();
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     /**
81      * Attaches this file object to its file resource.
82      */

83     protected void doAttach() throws Exception JavaDoc
84     {
85         if (resource == null)
86         {
87             setDavResource(null);
88         }
89     }
90
91     protected void doDetach() throws Exception JavaDoc
92     {
93         if (resource != null)
94         {
95             // clear cached data
96
redirectionResolved = false;
97             allowedMethods = null;
98
99             resource.close();
100             resource = null;
101         }
102     }
103
104     /**
105      * set the davResource
106      *
107      * @param resource
108      * @throws Exception
109      */

110     private void setDavResource(WebdavResource resource) throws Exception JavaDoc
111     {
112         redirectionResolved = false;
113
114         final URLFileName name = (URLFileName) getName();
115
116         if (resource == null)
117         {
118             // HttpURL url = new HttpURL(name.getHostName(), name.getPort(), name.getPath());
119
String JavaDoc 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         // if (bCheckExists)
131
{
132             /* now fill the dav properties */
133             String JavaDoc 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                         // permission denied on this object, but we might get some informations from the parent
146
processParentDavResource();
147                         return;
148                     }
149                     else
150                     {
151                         injectType(FileType.IMAGINARY);
152                     }
153                     return;
154                 }
155                 // handle the (maybe) redirected url
156
redirectionResolved = true;
157                 resource.getHttpURL().setEscapedPath(optionsMethod.getURI().getPath());
158
159                 setAllowedMethods(optionsMethod.getAllowedMethods());
160                 boolean exists = false;
161                 for (Enumeration JavaDoc enumeration = optionsMethod.getAllowedMethods(); enumeration.hasMoreElements();)
162                 {
163                     final String JavaDoc method = (String JavaDoc) enumeration.nextElement();
164                     // IIS allows GET even if the file is non existend - so changed to COPY
165
// if (method.equals("GET"))
166
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 JavaDoc 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 JavaDoc allowedMethods)
205     {
206         this.allowedMethods = new TreeSet JavaDoc();
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 JavaDoc method) throws IOException JavaDoc
220     {
221         if (allowedMethods == null)
222         {
223             getAllowedMethods();
224         }
225
226         return allowedMethods.contains(method);
227     }
228
229     private void resolveRedirection() throws IOException JavaDoc, 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             // after this our resource should be reset
260
parent.doListChildrenResolved();
261         }
262         catch (Exception JavaDoc e)
263         {
264             throw new FileSystemException(e);
265         }
266     }
267
268     /**
269      * Determines the type of the file, returns null if the file does not
270      * exist.
271      */

272     protected FileType doGetType() throws Exception JavaDoc
273     {
274         // return doGetType(null);
275
throw new IllegalStateException JavaDoc("this should not happen");
276     }
277
278     /**
279      * Lists the children of the file.
280      */

281     protected String JavaDoc[] doListChildren() throws Exception JavaDoc
282     {
283         // use doListChildrenResolved for performance
284
return null;
285     }
286
287     /**
288      * Lists the children of the file.
289      */

290     protected FileObject[] doListChildrenResolved() throws Exception JavaDoc
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 JavaDoc vfs = new ArrayList JavaDoc(children.length);
318         // WebdavFileObject[] vfs = new WebdavFileObject[children.length];
319
for (int i = 0; i < children.length; i++)
320         {
321             WebdavResource dav = children[i];
322
323             String JavaDoc davName = dav.getHttpURL().getEscapedName();
324             if ("".equals(davName))
325             {
326                 // current file
327
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[i] = fo;
338
vfs.add(fo);
339         }
340
341         return (WebdavFileObject[]) vfs.toArray(new WebdavFileObject[vfs.size()]);
342         // return vfs;
343
}
344
345     /**
346      * Creates this file as a folder.
347      */

348     protected void doCreateFolder() throws Exception JavaDoc
349     {
350         // Adjust resource path
351
//// resource.getHttpURL().setEscapedPath(getName().getPath() + '/');
352
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         // reread allowed methods
360
reattach();
361     }
362
363     /**
364      * Deletes the file.
365      */

366     protected void doDelete() throws Exception JavaDoc
367     {
368         resolveRedirection();
369         // final boolean ok = resource.deleteMethod(getName().getPathDecoded() /*url.getPath()*/);
370
final boolean ok = resource.deleteMethod();
371         if (!ok)
372         {
373             throw new FileSystemException("vfs.provider.webdav/delete-file.error", resource.getStatusMessage());
374         }
375
376         // reread allowed methods
377
reattach();
378     }
379
380     /**
381      * Rename the file.
382      */

383     protected void doRename(FileObject newfile) throws Exception JavaDoc
384     {
385         // final GenericFileName name = (GenericFileName) newfile.getName();
386
// HttpURL url = new HttpURL(name.getUserName(), name.getPassword(), name.getHostName(), name.getPort(), newfile.getName().getPath());
387
// String uri = url.getURI();
388

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         // reread allowed methods
396
reattach();
397     }
398
399     /**
400      * Creates an input stream to read the file content from.
401      */

402     protected InputStream JavaDoc doGetInputStream() throws Exception JavaDoc
403     {
404         return resource.getMethodData();
405     }
406
407     /**
408      * Creates an output stream to write the file content to.
409      */

410     protected OutputStream doGetOutputStream(boolean bAppend) throws Exception JavaDoc
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     /**
424      * Returns the size of the file content (in bytes).
425      */

426     protected long doGetContentSize() throws Exception JavaDoc
427     {
428         return resource.getGetContentLength();
429     }
430
431     /**
432      * An OutputStream that writes to a Webdav resource.
433      *
434      * @todo Use piped stream to avoid temporary file
435      */

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         /**
448          * Called after this stream is closed.
449          */

450         protected void onClose() throws IOException JavaDoc
451         {
452             // final ByteArrayOutputStream outstr = (ByteArrayOutputStream) out;
453

454             // Adjust the resource path (this file object may have been a folder)
455
resource.getHttpURL().setPath(getName().getPathDecoded());
456             // final boolean ok = resource.putMethod(outstr.toByteArray());
457
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                 // close and delete the temporary file
468
webdavTmp.close();
469                 webdavTmp.delete();
470             }
471         }
472     }
473
474     protected void handleCreate(final FileType newType) throws Exception JavaDoc
475     {
476         // imario@apache.org: this is to reread the webdav internal state
477
// Ill treat this as workaround
478
reattach();
479         super.handleCreate(newType);
480     }
481
482     /**
483      * refresh the webdav internals
484      *
485      * @throws FileSystemException
486      */

487     private void reattach() throws FileSystemException
488     {
489         try
490         {
491             doDetach();
492             doAttach();
493         }
494         catch (Exception JavaDoc e)
495         {
496             throw new FileSystemException(e);
497         }
498     }
499
500     /**
501      * Returns the last modified time of this file. Is only called if
502      * {@link #doGetType} does not return {@link FileType#IMAGINARY}.
503      */

504     protected long doGetLastModifiedTime() throws Exception JavaDoc
505     {
506         return resource.getGetLastModified();
507     }
508
509     /**
510      * Returns the properties of the Webdav resource.
511      */

512     protected Map JavaDoc doGetAttributes() throws Exception JavaDoc
513     {
514         final Map JavaDoc attributes = new HashMap JavaDoc();
515         final Enumeration JavaDoc e = resource.propfindMethod(DepthSupport.DEPTH_0);
516         while (e.hasMoreElements())
517         {
518             final XMLResponseMethodBase.Response response = (XMLResponseMethodBase.Response) e.nextElement();
519             final Enumeration JavaDoc 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 JavaDoc
531     {
532         return hasAllowedMethods("GET");
533     }
534
535     protected boolean doIsWriteable() throws Exception JavaDoc
536     {
537         // Again to be IIS compatible
538
// return hasAllowedMethods("POST");
539
return hasAllowedMethods("DELETE");
540     }
541
542     private void getAllowedMethods() throws IOException JavaDoc
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 JavaDoc
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 JavaDoc dis = null;
585
586         private InputStream JavaDoc 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 JavaDoc
596         {
597             return filePointer;
598         }
599
600         public void seek(long pos) throws IOException JavaDoc
601         {
602             if (pos == filePointer)
603             {
604                 // no change
605
return;
606             }
607
608             if (pos < 0)
609             {
610                 throw new FileSystemException(
611                     "vfs.provider/random-access-invalid-position.error",
612                     new Object JavaDoc[]{new Long JavaDoc(pos)});
613             }
614             if (dis != null)
615             {
616                 close();
617             }
618
619             filePointer = pos;
620         }
621
622         private void createStream() throws IOException JavaDoc
623         {
624             if (dis != null)
625             {
626                 return;
627             }
628
629             fileObject.resource.addRequestHeader("Range", "bytes="
630                 + filePointer + "-");
631             final InputStream JavaDoc 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 JavaDoc[]{
639                     fileObject.getName(), new Long JavaDoc(filePointer)});
640             }
641
642             mis = data;
643             dis = new DataInputStream JavaDoc(new FilterInputStream JavaDoc(mis)
644             {
645                 public int read() throws IOException JavaDoc
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 JavaDoc
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 JavaDoc
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 JavaDoc
678         {
679             if (dis != null)
680             {
681                 dis.close();
682                 dis = null;
683                 mis = null;
684             }
685         }
686
687         public long length() throws IOException JavaDoc
688         {
689             return fileObject.getContent().getSize();
690         }
691
692         public byte readByte() throws IOException JavaDoc
693         {
694             createStream();
695             byte data = dis.readByte();
696             return data;
697         }
698
699         public char readChar() throws IOException JavaDoc
700         {
701             createStream();
702             char data = dis.readChar();
703             return data;
704         }
705
706         public double readDouble() throws IOException JavaDoc
707         {
708             createStream();
709             double data = dis.readDouble();
710             return data;
711         }
712
713         public float readFloat() throws IOException JavaDoc
714         {
715             createStream();
716             float data = dis.readFloat();
717             return data;
718         }
719
720         public int readInt() throws IOException JavaDoc
721         {
722             createStream();
723             int data = dis.readInt();
724             return data;
725         }
726
727         public int readUnsignedByte() throws IOException JavaDoc
728         {
729             createStream();
730             int data = dis.readUnsignedByte();
731             return data;
732         }
733
734         public int readUnsignedShort() throws IOException JavaDoc
735         {
736             createStream();
737             int data = dis.readUnsignedShort();
738             return data;
739         }
740
741         public long readLong() throws IOException JavaDoc
742         {
743             createStream();
744             long data = dis.readLong();
745             return data;
746         }
747
748         public short readShort() throws IOException JavaDoc
749         {
750             createStream();
751             short data = dis.readShort();
752             return data;
753         }
754
755         public boolean readBoolean() throws IOException JavaDoc
756         {
757             createStream();
758             boolean data = dis.readBoolean();
759             return data;
760         }
761
762         public int skipBytes(int n) throws IOException JavaDoc
763         {
764             createStream();
765             int data = dis.skipBytes(n);
766             return data;
767         }
768
769         public void readFully(byte b[]) throws IOException JavaDoc
770         {
771             createStream();
772             dis.readFully(b);
773         }
774
775         public void readFully(byte b[], int off, int len) throws IOException JavaDoc
776         {
777             createStream();
778             dis.readFully(b, off, len);
779         }
780
781         public String JavaDoc readUTF() throws IOException JavaDoc
782         {
783             createStream();
784             String JavaDoc data = dis.readUTF();
785             return data;
786         }
787
788         public InputStream JavaDoc getInputStream() throws IOException JavaDoc
789         {
790             createStream();
791             return dis;
792         }
793     }
794
795 }
Popular Tags