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