View Javadoc

    1   // ========================================================================
    2   // Copyright 1996-2005 Mort Bay Consulting Pty. Ltd.
    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   // http://www.apache.org/licenses/LICENSE-2.0
    8   // Unless required by applicable law or agreed to in writing, software
    9   // distributed under the License is distributed on an "AS IS" BASIS,
    10  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    11  // See the License for the specific language governing permissions and
    12  // limitations under the License.
    13  // ========================================================================
    14  package org.mortbay.resource;
    15
    16  import java.io.File;
    17  import java.io.FileInputStream;
    18  import java.io.FileOutputStream;
    19  import java.io.IOException;
    20  import java.io.InputStream;
    21  import java.io.OutputStream;
    22  import java.net.MalformedURLException;
    23  import java.net.URI;
    24  import java.net.URISyntaxException;
    25  import java.net.URL;
    26  import java.net.URLConnection;
    27  import java.security.Permission;
    28
    29  import org.mortbay.log.Log;
    30  import org.mortbay.util.StringUtil;
    31  import org.mortbay.util.URIUtil;
    32
    33
    34  /* ------------------------------------------------------------ */
    35  /** File Resource.
    36   *
    37   * Handle resources of implied or explicit file type.
    38   * This class can check for aliasing in the filesystem (eg case
    39   * insensitivity).  By default this is turned on, or it can be controlled with the
    40   * "org.mortbay.util.FileResource.checkAliases" system parameter.
    41   *
    42   * @author Greg Wilkins (gregw)
    43   */
    44  public class FileResource extends URLResource
    45  {
    46      private static boolean __checkAliases;
    47      static
    48      {
    49          __checkAliases=
    50              "true".equalsIgnoreCase
    51              (System.getProperty("org.mortbay.util.FileResource.checkAliases","true"));
    52
    53         if (__checkAliases)
    54              Log.debug("Checking Resource aliases");
    55      }
    56
    57      /* ------------------------------------------------------------ */
    58      private File _file;
    59      private transient URL _alias=null;
    60      private transient boolean _aliasChecked=false;
    61
    62      /* ------------------------------------------------------------------------------- */
    63      /** setCheckAliases.
    64       * @param checkAliases True of resource aliases are to be checked for (eg case insensitivity or 8.3 short names) and treated as not found.
    65       */
    66      public static void setCheckAliases(boolean checkAliases)
    67      {
    68          __checkAliases=checkAliases;
    69      }
    70
    71      /* ------------------------------------------------------------------------------- */
    72      /** getCheckAliases.
    73       * @return True of resource aliases are to be checked for (eg case insensitivity or 8.3 short names) and treated as not found.
    74       */
    75      public static boolean getCheckAliases()
    76      {
    77          return __checkAliases;
    78      }
    79
    80      /* -------------------------------------------------------- */
    81      public FileResource(URL url)
    82          throws IOException, URISyntaxException
    83      {
    84          super(url,null);
    85
    86          try
    87          {
    88              // Try standard API to convert URL to file.
    89              _file =new File(new URI(url.toString()));
    90          }
    91          catch (Exception e)
    92          {
    93              Log.ignore(e);
    94              try
    95              {
    96                  // Assume that File.toURL produced unencoded chars. So try
    97                  // encoding them.
    98                  String file_url="file:"+URIUtil.encodePath(url.toString().substring(5));
    99                  URI uri = new URI(file_url);
    100                 if (uri.getAuthority()==null)
    101                     _file = new File(uri);
    102                 else
    103                     _file = new File("//"+uri.getAuthority()+URIUtil.decodePath(url.getFile()));
    104             }
    105             catch (Exception e2)
    106             {
    107                 Log.ignore(e2);
    108
    109                 // Still can't get the file.  Doh! try good old hack!
    110                 checkConnection();
    111                 Permission perm = _connection.getPermission();
    112                 _file = new File(perm==null?url.getFile():perm.getName());
    113             }
    114         }
    115         if (_file.isDirectory())
    116         {
    117             if (!_urlString.endsWith("/"))
    118                 _urlString=_urlString+"/";
    119         }
    120         else
    121         {
    122             if (_urlString.endsWith("/"))
    123                 _urlString=_urlString.substring(0,_urlString.length()-1);
    124         }
    125
    126     }
    127
    128     /* -------------------------------------------------------- */
    129     FileResource(URL url, URLConnection connection, File file)
    130     {
    131         super(url,connection);
    132         _file=file;
    133         if (_file.isDirectory() && !_urlString.endsWith("/"))
    134             _urlString=_urlString+"/";
    135     }
    136
    137     /* -------------------------------------------------------- */
    138     public Resource addPath(String path)
    139         throws IOException,MalformedURLException
    140     {
    141         URLResource r=null;
    142         String url=null;
    143
    144         path = org.mortbay.util.URIUtil.canonicalPath(path);
    145
    146         if (!isDirectory())
    147         {
    148             r=(FileResource)super.addPath(path);
    149             url=r._urlString;
    150         }
    151         else
    152         {
    153             if (path==null)
    154                 throw new MalformedURLException();
    155
    156             // treat all paths being added as relative
    157             String rel=path;
    158             if (path.startsWith("/"))
    159                 rel = path.substring(1);
    160
    161             url=URIUtil.addPaths(_urlString,URIUtil.encodePath(rel));
    162             r=(URLResource)Resource.newResource(url);
    163         }
    164
    165         String encoded=URIUtil.encodePath(path);
    166         int expected=r.toString().length()-encoded.length();
    167         int index = r._urlString.lastIndexOf(encoded, expected);
    168
    169         if (expected!=index && ((expected-1)!=index || path.endsWith("/") || !r.isDirectory()))
    170         {
    171             if (!(r instanceof BadResource))
    172             {
    173                 ((FileResource)r)._alias=new URL(url);
    174                 ((FileResource)r)._aliasChecked=true;
    175             }
    176         }
    177         return r;
    178     }
    179
    180
    181     /* ------------------------------------------------------------ */
    182     public URL getAlias()
    183     {
    184         if (__checkAliases && !_aliasChecked)
    185         {
    186             try
    187             {
    188                 String abs=_file.getAbsolutePath();
    189                 String can=_file.getCanonicalPath();
    190
    191                 if (abs.length()!=can.length() || !abs.equals(can))
    192                     _alias=new File(can).toURI().toURL();
    193
    194                 _aliasChecked=true;
    195
    196                 if (_alias!=null && Log.isDebugEnabled())
    197                 {
    198                     Log.debug("ALIAS abs="+abs);
    199                     Log.debug("ALIAS can="+can);
    200                 }
    201             }
    202             catch(Exception e)
    203             {
    204                 Log.warn(Log.EXCEPTION,e);
    205                 return getURL();
    206             }
    207         }
    208         return _alias;
    209     }
    210
    211     /* -------------------------------------------------------- */
    212     /**
    213      * Returns true if the resource exists.
    214      */
    215     public boolean exists()
    216     {
    217         return _file.exists();
    218     }
    219
    220     /* -------------------------------------------------------- */
    221     /**
    222      * Returns the last modified time
    223      */
    224     public long lastModified()
    225     {
    226         return _file.lastModified();
    227     }
    228
    229     /* -------------------------------------------------------- */
    230     /**
    231      * Returns true if the respresenetd resource is a container/directory.
    232      */
    233     public boolean isDirectory()
    234     {
    235         return _file.isDirectory();
    236     }
    237
    238     /* --------------------------------------------------------- */
    239     /**
    240      * Return the length of the resource
    241      */
    242     public long length()
    243     {
    244         return _file.length();
    245     }
    246
    247
    248     /* --------------------------------------------------------- */
    249     /**
    250      * Returns the name of the resource
    251      */
    252     public String getName()
    253     {
    254         return _file.getAbsolutePath();
    255     }
    256
    257     /* ------------------------------------------------------------ */
    258     /**
    259      * Returns an File representing the given resource or NULL if this
    260      * is not possible.
    261      */
    262     public File getFile()
    263     {
    264         return _file;
    265     }
    266
    267     /* --------------------------------------------------------- */
    268     /**
    269      * Returns an input stream to the resource
    270      */
    271     public InputStream getInputStream() throws IOException
    272     {
    273         return new FileInputStream(_file);
    274     }
    275
    276     /* --------------------------------------------------------- */
    277     /**
    278      * Returns an output stream to the resource
    279      */
    280     public OutputStream getOutputStream()
    281         throws java.io.IOException, SecurityException
    282     {
    283         return new FileOutputStream(_file);
    284     }
    285
    286     /* --------------------------------------------------------- */
    287     /**
    288      * Deletes the given resource
    289      */
    290     public boolean delete()
    291         throws SecurityException
    292     {
    293         return _file.delete();
    294     }
    295
    296     /* --------------------------------------------------------- */
    297     /**
    298      * Rename the given resource
    299      */
    300     public boolean renameTo( Resource dest)
    301         throws SecurityException
    302     {
    303         if( dest instanceof FileResource)
    304             return _file.renameTo( ((FileResource)dest)._file);
    305         else
    306             return false;
    307     }
    308
    309     /* --------------------------------------------------------- */
    310     /**
    311      * Returns a list of resources contained in the given resource
    312      */
    313     public String[] list()
    314     {
    315         String[] list =_file.list();
    316         if (list==null)
    317             return null;
    318         for (int i=list.length;i-->0;)
    319         {
    320             if (new File(_file,list[i]).isDirectory() &&
    321                 !list[i].endsWith("/"))
    322                 list[i]+="/";
    323         }
    324         return list;
    325     }
    326
    327     /* ------------------------------------------------------------ */
    328     /** Encode according to this resource type.
    329      * File URIs are encoded.
    330      * @param uri URI to encode.
    331      * @return The uri unchanged.
    332      */
    333     public String encode(String uri)
    334     {
    335         return uri;
    336     }
    337
    338     /* ------------------------------------------------------------ */
    339     /**
    340      * @param o
    341      * @return <code>true</code> of the object <code>o</code> is a {@link FileResource} pointing to the same file as this resource.
    342      */
    343     public boolean equals( Object o)
    344     {
    345         if (this == o)
    346             return true;
    347
    348         if (null == o || ! (o instanceof FileResource))
    349             return false;
    350
    351         FileResource f=(FileResource)o;
    352         return f._file == _file || (null != _file && _file.equals(f._file));
    353     }
    354
    355     /* ------------------------------------------------------------ */
    356     /**
    357      * @return the hashcode.
    358      */
    359     public int hashCode()
    360     {
    361        return null == _file ? super.hashCode() : _file.hashCode();
    362     }
    363 }