View Javadoc

    1   /*
    2    * Licensed to the Apache Software Foundation (ASF) under one or more
    3    * contributor license agreements.  See the NOTICE file distributed with
    4    * this work for additional information regarding copyright ownership.
    5    * The ASF licenses this file to You under the Apache License, Version 2.0
    6    * (the "License"); you may not use this file except in compliance with
    7    * the License.  You may obtain a copy of the License at
    8    *
    9    *      http://www.apache.org/licenses/LICENSE-2.0
    10   *
    11   * Unless required by applicable law or agreed to in writing, software
    12   * distributed under the License is distributed on an "AS IS" BASIS,
    13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    14   * See the License for the specific language governing permissions and
    15   * limitations under the License.
    16   */
    17  package org.apache.commons.vfs.provider.http;
    18
    19  import org.apache.commons.httpclient.Header;
    20  import org.apache.commons.httpclient.HttpClient;
    21  import org.apache.commons.httpclient.HttpMethod;
    22  import org.apache.commons.httpclient.URIException;
    23  import org.apache.commons.httpclient.methods.GetMethod;
    24  import org.apache.commons.httpclient.methods.HeadMethod;
    25  import org.apache.commons.httpclient.util.DateParser;
    26  import org.apache.commons.httpclient.util.URIUtil;
    27  import org.apache.commons.vfs.FileContentInfoFactory;
    28  import org.apache.commons.vfs.FileName;
    29  import org.apache.commons.vfs.FileSystemException;
    30  import org.apache.commons.vfs.FileType;
    31  import org.apache.commons.vfs.RandomAccessContent;
    32  import org.apache.commons.vfs.provider.AbstractFileObject;
    33  import org.apache.commons.vfs.provider.URLFileName;
    34  import org.apache.commons.vfs.util.MonitorInputStream;
    35  import org.apache.commons.vfs.util.RandomAccessMode;
    36
    37  import java.io.IOException;
    38  import java.io.InputStream;
    39  import java.net.HttpURLConnection;
    40
    41  /***
    42   * A file object backed by commons httpclient.
    43   *
    44   * @author <a href="mailto:adammurdoch@apache.org">Adam Murdoch</a>
    45   * @version $Revision: 480428 $ $Date: 2006-11-29 07:15:24 +0100 (Mi, 29 Nov 2006) $
    46   * @todo status codes
    47   */
    48  public class HttpFileObject
    49      extends AbstractFileObject
    50  {
    51      private final HttpFileSystem fileSystem;
    52      private final String urlCharset;
    53      private HeadMethod method;
    54
    55      protected HttpFileObject(final FileName name,
    56                               final HttpFileSystem fileSystem)
    57      {
    58          super(name, fileSystem);
    59          this.fileSystem = fileSystem;
    60          urlCharset = HttpFileSystemConfigBuilder.getInstance().getUrlCharset(getFileSystem().getFileSystemOptions());
    61      }
    62
    63      /***
    64       * Detaches this file object from its file resource.
    65       */
    66      protected void doDetach()
    67          throws Exception
    68      {
    69          method = null;
    70      }
    71
    72      /***
    73       * Determines the type of this file.  Must not return null.  The return
    74       * value of this method is cached, so the implementation can be expensive.
    75       */
    76      protected FileType doGetType()
    77          throws Exception
    78      {
    79          // Use the HEAD method to probe the file.
    80          method = new HeadMethod();
    81          setupMethod(method);
    82          final HttpClient client = fileSystem.getClient();
    83          final int status = client.executeMethod(method);
    84          method.releaseConnection();
    85          if (status == HttpURLConnection.HTTP_OK)
    86          {
    87              return FileType.FILE;
    88          }
    89          else if (status == HttpURLConnection.HTTP_NOT_FOUND
    90              || status == HttpURLConnection.HTTP_GONE)
    91          {
    92              return FileType.IMAGINARY;
    93          }
    94          else
    95          {
    96              throw new FileSystemException("vfs.provider.http/head.error", getName());
    97          }
    98      }
    99
    100     /***
    101      * Lists the children of this file.
    102      */
    103     protected String[] doListChildren()
    104         throws Exception
    105     {
    106         throw new Exception("Not implemented.");
    107     }
    108
    109     /***
    110      * Returns the size of the file content (in bytes).
    111      */
    112     protected long doGetContentSize()
    113         throws Exception
    114     {
    115         final Header header = method.getResponseHeader("content-length");
    116         if (header == null)
    117         {
    118             // Assume 0 content-length
    119             return 0;
    120         }
    121         return Integer.parseInt(header.getValue());
    122     }
    123
    124     /***
    125      * Returns the last modified time of this file.
    126      * <p/>
    127      * This implementation throws an exception.
    128      */
    129     protected long doGetLastModifiedTime()
    130         throws Exception
    131     {
    132         final Header header = method.getResponseHeader("last-modified");
    133         if (header == null)
    134         {
    135             throw new FileSystemException("vfs.provider.http/last-modified.error", getName());
    136         }
    137         return DateParser.parseDate(header.getValue()).getTime();
    138     }
    139
    140     /***
    141      * Creates an input stream to read the file content from.  Is only called
    142      * if {@link #doGetType} returns {@link FileType#FILE}.
    143      * <p/>
    144      * <p>It is guaranteed that there are no open output streams for this file
    145      * when this method is called.
    146      * <p/>
    147      * <p>The returned stream does not have to be buffered.
    148      */
    149     protected InputStream doGetInputStream()
    150         throws Exception
    151     {
    152         final GetMethod getMethod = new GetMethod();
    153         setupMethod(getMethod);
    154         final int status = fileSystem.getClient().executeMethod(getMethod);
    155         if (status != HttpURLConnection.HTTP_OK)
    156         {
    157             throw new FileSystemException("vfs.provider.http/get.error", getName());
    158         }
    159
    160         return new HttpInputStream(getMethod);
    161     }
    162
    163     protected RandomAccessContent doGetRandomAccessContent(final RandomAccessMode mode) throws Exception
    164     {
    165         return new HttpRandomAccesContent(this, mode);
    166     }
    167
    168     /***
    169      * Prepares a Method object.
    170      */
    171     void setupMethod(final HttpMethod method) throws FileSystemException, URIException
    172     {
    173         String pathEncoded = ((URLFileName) getName()).getPathQueryEncoded(urlCharset);
    174         method.setPath(pathEncoded);
    175         method.setFollowRedirects(true);
    176         method.setRequestHeader("User-Agent", "Jakarta-Commons-VFS");
    177     }
    178
    179     protected String encodePath(final String decodedPath) throws URIException
    180     {
    181         String pathEncoded = URIUtil.encodePath(decodedPath);
    182         return pathEncoded;
    183     }
    184
    185     /***
    186      * An InputStream that cleans up the HTTP connection on close.
    187      */
    188     static class HttpInputStream
    189         extends MonitorInputStream
    190     {
    191         private final GetMethod method;
    192
    193         public HttpInputStream(final GetMethod method)
    194             throws IOException
    195         {
    196             super(method.getResponseBodyAsStream());
    197             this.method = method;
    198         }
    199
    200         /***
    201          * Called after the stream has been closed.
    202          */
    203         protected void onClose()
    204             throws IOException
    205         {
    206             method.releaseConnection();
    207         }
    208     }
    209
    210
    211     protected FileContentInfoFactory getFileContentInfoFactory()
    212     {
    213         return new HttpFileContentInfoFactory();
    214     }
    215
    216     HeadMethod getHeadMethod()
    217     {
    218         return method;
    219     }
    220
    221     /*
    222     protected Map doGetAttributes() throws Exception
    223     {
    224         TreeMap map = new TreeMap();
    225
    226         Header contentType = method.getResponseHeader("content-type");
    227         if (contentType != null)
    228         {
    229             HeaderElement[] element = contentType.getValues();
    230             if (element != null && element.length > 0)
    231             {
    232                 map.put("content-type", element[0].getName());
    233             }
    234         }
    235
    236         map.put("content-encoding", method.getResponseCharSet());
    237         return map;
    238     }
    239     */
    240 }