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.IOException;
    18  import java.net.JarURLConnection;
    19  import java.net.URL;
    20  import java.util.ArrayList;
    21  import java.util.Enumeration;
    22  import java.util.jar.JarEntry;
    23  import java.util.jar.JarFile;
    24
    25  import org.mortbay.log.Log;
    26
    27  /* ------------------------------------------------------------ */
    28  class JarFileResource extends JarResource
    29  {
    30
    31      transient JarFile _jarFile;
    32      transient File _file;
    33      transient String[] _list;
    34      transient JarEntry _entry;
    35      transient boolean _directory;
    36      transient String _jarUrl;
    37      transient String _path;
    38      transient boolean _exists;
    39
    40
    41      /* -------------------------------------------------------- */
    42      JarFileResource(URL url)
    43      {
    44          super(url);
    45      }
    46
    47      JarFileResource(URL url, boolean useCaches)
    48      {
    49          super(url, useCaches);
    50      }
    51
    52
    53      /* ------------------------------------------------------------ */
    54      public synchronized void release()
    55      {
    56          _list=null;
    57          _entry=null;
    58          _file=null;
    59          _jarFile=null;
    60          super.release();
    61      }
    62
    63      /* ------------------------------------------------------------ */
    64      protected boolean checkConnection()
    65      {
    66          try{
    67              super.checkConnection();
    68          }
    69          finally
    70          {
    71              if (_jarConnection==null)
    72              {
    73                  _entry=null;
    74                  _file=null;
    75                  _jarFile=null;
    76                  _list=null;
    77              }
    78          }
    79          return _jarFile!=null;
    80      }
    81
    82
    83      /* ------------------------------------------------------------ */
    84      protected void newConnection()
    85          throws IOException
    86      {
    87          super.newConnection();
    88
    89          _entry=null;
    90          _file=null;
    91          _jarFile=null;
    92          _list=null;
    93
    94          int sep = _urlString.indexOf("!/");
    95          _jarUrl=_urlString.substring(0,sep+2);
    96          _path=_urlString.substring(sep+2);
    97          if (_path.length()==0)
    98              _path=null;
    99          _jarFile=_jarConnection.getJarFile();
    100         _file=new File(_jarFile.getName());
    101     }
    102
    103
    104     /* ------------------------------------------------------------ */
    105     /**
    106      * Returns true if the respresenetd resource exists.
    107      */
    108     public boolean exists()
    109     {
    110         if (_exists)
    111             return true;
    112
    113         if (_urlString.endsWith("!/"))
    114         {
    115
    116             String file_url=_urlString.substring(4,_urlString.length()-2);
    117             try{return newResource(file_url).exists();}
    118             catch(Exception e) {Log.ignore(e); return false;}
    119         }
    120
    121         boolean check=checkConnection();
    122
    123         // Is this a root URL?
    124         if (_jarUrl!=null && _path==null)
    125         {
    126             // Then if it exists it is a directory
    127             _directory=check;
    128             return true;
    129         }
    130         else
    131         {
    132             // Can we find a file for it?
    133             JarFile jarFile=null;
    134             if (check)
    135                 // Yes
    136                 jarFile=_jarFile;
    137             else
    138             {
    139                 // No - so lets look if the root entry exists.
    140                 try
    141                 {
    142                     JarURLConnection c=(JarURLConnection)((new URL(_jarUrl)).openConnection());
    143                     c.setUseCaches(getUseCaches());
    144                     jarFile=c.getJarFile();
    145                 }
    146                 catch(Exception e)
    147                 {
    148                        Log.ignore(e);
    149                 }
    150             }
    151
    152             // Do we need to look more closely?
    153             if (jarFile!=null && _entry==null && !_directory)
    154             {
    155                 // OK - we have a JarFile, lets look at the entries for our path
    156                 Enumeration e=jarFile.entries();
    157                 while(e.hasMoreElements())
    158                 {
    159                     JarEntry entry = (JarEntry) e.nextElement();
    160                     String name=entry.getName().replace('\\','/');
    161
    162                     // Do we have a match
    163                     if (name.equals(_path))
    164                     {
    165                         _entry=entry;
    166                         // Is the match a directory
    167                         _directory=_path.endsWith("/");
    168                         break;
    169                     }
    170                     else if (_path.endsWith("/"))
    171                     {
    172                         if (name.startsWith(_path))
    173                         {
    174                             _directory=true;
    175                             break;
    176                         }
    177                     }
    178                     else if (name.startsWith(_path) && name.length()>_path.length() && name.charAt(_path.length())=='/')
    179                     {
    180                         _directory=true;
    181                         break;
    182                     }
    183                 }
    184             }
    185         }
    186
    187         _exists= ( _directory || _entry!=null);
    188         return _exists;
    189     }
    190
    191
    192     /* ------------------------------------------------------------ */
    193     /**
    194      * Returns true if the represented resource is a container/directory.
    195      * If the resource is not a file, resources ending with "/" are
    196      * considered directories.
    197      */
    198     public boolean isDirectory()
    199     {
    200         return _urlString.endsWith("/") || exists() && _directory;
    201     }
    202
    203     /* ------------------------------------------------------------ */
    204     /**
    205      * Returns the last modified time
    206      */
    207     public long lastModified()
    208     {
    209         if (checkConnection() && _file!=null)
    210             return _file.lastModified();
    211         return -1;
    212     }
    213
    214     /* ------------------------------------------------------------ */
    215     public synchronized String[] list()
    216     {
    217
    218         if(isDirectory() && _list==null)
    219         {
    220             ArrayList list = new ArrayList(32);
    221
    222             checkConnection();
    223
    224             JarFile jarFile=_jarFile;
    225             if(jarFile==null)
    226             {
    227                 try
    228                 {
    229                     JarURLConnection jc=(JarURLConnection)((new URL(_jarUrl)).openConnection());
    230                     jc.setUseCaches(getUseCaches());
    231                     jarFile=jc.getJarFile();
    232                 }
    233                 catch(Exception e)
    234                 {
    235                      Log.ignore(e);
    236                 }
    237             }
    238
    239             Enumeration e=jarFile.entries();
    240             String dir=_urlString.substring(_urlString.indexOf("!/")+2);
    241             while(e.hasMoreElements())
    242             {
    243
    244                 JarEntry entry = (JarEntry) e.nextElement();
    245                 String name=entry.getName().replace('\\','/');
    246                 if(!name.startsWith(dir) || name.length()==dir.length())
    247                 {
    248                     continue;
    249                 }
    250                 String listName=name.substring(dir.length());
    251                 int dash=listName.indexOf('/');
    252                 if (dash>=0)
    253                 {
    254                     //when listing jar:file urls, you get back one
    255                     //entry for the dir itself, which we ignore
    256                     if (dash==0 && listName.length()==1)
    257                         continue;
    258                     //when listing jar:file urls, all files and
    259                     //subdirs have a leading /, which we remove
    260                     if (dash==0)
    261                         listName=listName.substring(dash+1, listName.length());
    262                     else
    263                         listName=listName.substring(0,dash+1);
    264
    265                     if (list.contains(listName))
    266                         continue;
    267                 }
    268
    269                 list.add(listName);
    270             }
    271
    272             _list=new String[list.size()];
    273             list.toArray(_list);
    274         }
    275         return _list;
    276     }
    277
    278     /* ------------------------------------------------------------ */
    279     /**
    280      * Return the length of the resource
    281      */
    282     public long length()
    283     {
    284         if (isDirectory())
    285             return -1;
    286
    287         if (_entry!=null)
    288             return _entry.getSize();
    289
    290         return -1;
    291     }
    292
    293     /* ------------------------------------------------------------ */
    294     /** Encode according to this resource type.
    295      * File URIs are not encoded.
    296      * @param uri URI to encode.
    297      * @return The uri unchanged.
    298      */
    299     public String encode(String uri)
    300     {
    301         return uri;
    302     }
    303
    304
    305     /**
    306      * Take a Resource that possibly might use URLConnection caching
    307      * and turn it into one that doesn't.
    308      * @param resource
    309      * @return
    310      */
    311     public static Resource getNonCachingResource (Resource resource)
    312     {
    313         if (!(resource instanceof JarFileResource))
    314             return resource;
    315
    316         JarFileResource oldResource = (JarFileResource)resource;
    317
    318         JarFileResource newResource = new JarFileResource(oldResource.getURL(), false);
    319         return newResource;
    320
    321     }
    322 }
    323
    324
    325
    326
    327
    328
    329
    330