View Javadoc

1   //
2   //  ========================================================================
3   //  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
4   //  ------------------------------------------------------------------------
5   //  All rights reserved. This program and the accompanying materials
6   //  are made available under the terms of the Eclipse Public License v1.0
7   //  and Apache License v2.0 which accompanies this distribution.
8   //
9   //      The Eclipse Public License is available at
10  //      http://www.eclipse.org/legal/epl-v10.html
11  //
12  //      The Apache License v2.0 is available at
13  //      http://www.opensource.org/licenses/apache2.0.php
14  //
15  //  You may elect to redistribute this code under either of these licenses.
16  //  ========================================================================
17  //
18  
19  package org.eclipse.jetty.util.resource;
20  
21  import java.io.File;
22  import java.io.IOException;
23  import java.io.InputStream;
24  import java.net.MalformedURLException;
25  import java.net.URL;
26  import java.net.URLConnection;
27  import java.nio.channels.ReadableByteChannel;
28  import java.security.Permission;
29  
30  import org.eclipse.jetty.util.URIUtil;
31  import org.eclipse.jetty.util.log.Log;
32  import org.eclipse.jetty.util.log.Logger;
33  
34  /* ------------------------------------------------------------ */
35  /** Abstract resource class.
36   */
37  public class URLResource extends Resource
38  {
39      private static final Logger LOG = Log.getLogger(URLResource.class);
40      protected final URL _url;
41      protected final String _urlString;
42      
43      protected URLConnection _connection;
44      protected InputStream _in=null;
45      transient boolean _useCaches = Resource.__defaultUseCaches;
46      
47      /* ------------------------------------------------------------ */
48      protected URLResource(URL url, URLConnection connection)
49      {
50          _url = url;
51          _urlString=_url.toExternalForm();
52          _connection=connection;
53      }
54      
55      /* ------------------------------------------------------------ */
56      protected URLResource (URL url, URLConnection connection, boolean useCaches)
57      {
58          this (url, connection);
59          _useCaches = useCaches;
60      }
61  
62      /* ------------------------------------------------------------ */
63      protected synchronized boolean checkConnection()
64      {
65          if (_connection==null)
66          {
67              try{
68                  _connection=_url.openConnection();
69                  _connection.setUseCaches(_useCaches);
70              }
71              catch(IOException e)
72              {
73                  LOG.ignore(e);
74              }
75          }
76          return _connection!=null;
77      }
78  
79      /* ------------------------------------------------------------ */
80      /** Release any resources held by the resource.
81       */
82      @Override
83      public synchronized void close()
84      {
85          if (_in!=null)
86          {
87              try{_in.close();}catch(IOException e){LOG.ignore(e);}
88              _in=null;
89          }
90  
91          if (_connection!=null)
92              _connection=null;
93      }
94  
95      /* ------------------------------------------------------------ */
96      /**
97       * Returns true if the represented resource exists.
98       */
99      @Override
100     public boolean exists()
101     {
102         try
103         {
104             synchronized(this)
105             {
106                 if (checkConnection() && _in==null )
107                     _in = _connection.getInputStream();
108             }
109         }
110         catch (IOException e)
111         {
112             LOG.ignore(e);
113         }
114         return _in!=null;
115     }
116 
117     /* ------------------------------------------------------------ */
118     /**
119      * Returns true if the represented resource is a container/directory.
120      * If the resource is not a file, resources ending with "/" are
121      * considered directories.
122      */
123     @Override
124     public boolean isDirectory()
125     {
126         return exists() && _urlString.endsWith("/");
127     }
128 
129 
130     /* ------------------------------------------------------------ */
131     /**
132      * Returns the last modified time
133      */
134     @Override
135     public long lastModified()
136     {
137         if (checkConnection())
138             return _connection.getLastModified();
139         return -1;
140     }
141 
142 
143     /* ------------------------------------------------------------ */
144     /**
145      * Return the length of the resource
146      */
147     @Override
148     public long length()
149     {
150         if (checkConnection())
151             return _connection.getContentLength();
152         return -1;
153     }
154 
155     /* ------------------------------------------------------------ */
156     /**
157      * Returns an URL representing the given resource
158      */
159     @Override
160     public URL getURL()
161     {
162         return _url;
163     }
164 
165     /* ------------------------------------------------------------ */
166     /**
167      * Returns an File representing the given resource or NULL if this
168      * is not possible.
169      */
170     @Override
171     public File getFile()
172         throws IOException
173     {
174         // Try the permission hack
175         if (checkConnection())
176         {
177             Permission perm = _connection.getPermission();
178             if (perm instanceof java.io.FilePermission)
179                 return new File(perm.getName());
180         }
181 
182         // Try the URL file arg
183         try {return new File(_url.getFile());}
184         catch(Exception e) {LOG.ignore(e);}
185 
186         // Don't know the file
187         return null;    
188     }
189 
190     /* ------------------------------------------------------------ */
191     /**
192      * Returns the name of the resource
193      */
194     @Override
195     public String getName()
196     {
197         return _url.toExternalForm();
198     }
199 
200     
201     /* ------------------------------------------------------------ */
202     /**
203      * Returns an input stream to the resource. The underlying 
204      * url connection will be nulled out to prevent re-use.
205      */
206     @Override
207     public synchronized InputStream getInputStream()
208         throws java.io.IOException
209     {
210         return getInputStream (true); //backwards compatibility
211     }
212     
213     
214  
215     /* ------------------------------------------------------------ */
216     /**
217      * Returns an input stream to the resource, optionally nulling
218      * out the underlying url connection. If the connection is not
219      * nulled out, a subsequent call to getInputStream() may return
220      * an existing and already in-use input stream - this depends on
221      * the url protocol. Eg JarURLConnection does not reuse inputstreams.
222      * 
223      * @param resetConnection if true the connection field is set to null
224      * @return the inputstream for this resource
225      * @throws IOException if unable to open the input stream
226      */
227     protected synchronized InputStream getInputStream(boolean resetConnection)
228         throws IOException
229     {
230         if (!checkConnection())
231             throw new IOException( "Invalid resource");
232 
233         try
234         {    
235             if( _in != null)
236             {
237                 InputStream in = _in;
238                 _in=null;
239                 return in;
240             }
241             return _connection.getInputStream();
242         }
243         finally
244         {
245             if (resetConnection)
246             {
247                 _connection=null;
248                 if (LOG.isDebugEnabled()) LOG.debug("Connection nulled");
249             }
250         }
251     }
252 
253     /* ------------------------------------------------------------ */
254     @Override
255     public ReadableByteChannel getReadableByteChannel() throws IOException
256     {
257         return null;
258     }
259 
260     /* ------------------------------------------------------------ */
261     /**
262      * Deletes the given resource
263      */
264     @Override
265     public boolean delete()
266         throws SecurityException
267     {
268         throw new SecurityException( "Delete not supported");
269     }
270 
271     /* ------------------------------------------------------------ */
272     /**
273      * Rename the given resource
274      */
275     @Override
276     public boolean renameTo( Resource dest)
277         throws SecurityException
278     {
279         throw new SecurityException( "RenameTo not supported");
280     }
281 
282     /* ------------------------------------------------------------ */
283     /**
284      * Returns a list of resource names contained in the given resource
285      */
286     @Override
287     public String[] list()
288     {
289         return null;
290     }
291 
292     /* ------------------------------------------------------------ */
293     /**
294      * Returns the resource contained inside the current resource with the
295      * given name
296      */
297     @Override
298     public Resource addPath(String path)
299         throws IOException,MalformedURLException
300     {
301         if (path==null)
302             return null;
303 
304         path = URIUtil.canonicalPath(path);
305 
306         return newResource(URIUtil.addPaths(_url.toExternalForm(),URIUtil.encodePath(path)), _useCaches);
307     }
308 
309     /* ------------------------------------------------------------ */
310     @Override
311     public String toString()
312     {
313         return _urlString;
314     }
315 
316     /* ------------------------------------------------------------ */
317     @Override
318     public int hashCode()
319     {
320         return _urlString.hashCode();
321     }
322     
323     /* ------------------------------------------------------------ */
324     @Override
325     public boolean equals( Object o)
326     {
327         return o instanceof URLResource && _urlString.equals(((URLResource)o)._urlString);
328     }
329 
330     /* ------------------------------------------------------------ */
331     public boolean getUseCaches ()
332     {
333         return _useCaches;
334     }
335 
336     /* ------------------------------------------------------------ */
337     @Override
338     public boolean isContainedIn (Resource containingResource) throws MalformedURLException
339     {
340         return false;
341     }
342 }