1 //
2 // ========================================================================
3 // Copyright (c) 1995-2013 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.io.OutputStream;
25 import java.net.MalformedURLException;
26 import java.net.URL;
27 import java.net.URLConnection;
28 import java.nio.channels.ReadableByteChannel;
29 import java.security.Permission;
30
31 import org.eclipse.jetty.util.URIUtil;
32 import org.eclipse.jetty.util.log.Log;
33 import org.eclipse.jetty.util.log.Logger;
34
35 /* ------------------------------------------------------------ */
36 /** Abstract resource class.
37 */
38 public class URLResource extends Resource
39 {
40 private static final Logger LOG = Log.getLogger(URLResource.class);
41 protected URL _url;
42 protected String _urlString;
43
44 protected URLConnection _connection;
45 protected InputStream _in=null;
46 transient boolean _useCaches = Resource.__defaultUseCaches;
47
48 /* ------------------------------------------------------------ */
49 protected URLResource(URL url, URLConnection connection)
50 {
51 _url = url;
52 _urlString=_url.toString();
53 _connection=connection;
54 }
55
56 /* ------------------------------------------------------------ */
57 protected URLResource (URL url, URLConnection connection, boolean useCaches)
58 {
59 this (url, connection);
60 _useCaches = useCaches;
61 }
62
63 /* ------------------------------------------------------------ */
64 protected synchronized boolean checkConnection()
65 {
66 if (_connection==null)
67 {
68 try{
69 _connection=_url.openConnection();
70 _connection.setUseCaches(_useCaches);
71 }
72 catch(IOException e)
73 {
74 LOG.ignore(e);
75 }
76 }
77 return _connection!=null;
78 }
79
80 /* ------------------------------------------------------------ */
81 /** Release any resources held by the resource.
82 */
83 @Override
84 public synchronized void release()
85 {
86 if (_in!=null)
87 {
88 try{_in.close();}catch(IOException e){LOG.ignore(e);}
89 _in=null;
90 }
91
92 if (_connection!=null)
93 _connection=null;
94 }
95
96 /* ------------------------------------------------------------ */
97 /**
98 * Returns true if the represented resource exists.
99 */
100 @Override
101 public boolean exists()
102 {
103 try
104 {
105 synchronized(this)
106 {
107 if (checkConnection() && _in==null )
108 _in = _connection.getInputStream();
109 }
110 }
111 catch (IOException e)
112 {
113 LOG.ignore(e);
114 }
115 return _in!=null;
116 }
117
118 /* ------------------------------------------------------------ */
119 /**
120 * Returns true if the respresenetd resource is a container/directory.
121 * If the resource is not a file, resources ending with "/" are
122 * considered directories.
123 */
124 @Override
125 public boolean isDirectory()
126 {
127 return exists() && _url.toString().endsWith("/");
128 }
129
130
131 /* ------------------------------------------------------------ */
132 /**
133 * Returns the last modified time
134 */
135 @Override
136 public long lastModified()
137 {
138 if (checkConnection())
139 return _connection.getLastModified();
140 return -1;
141 }
142
143
144 /* ------------------------------------------------------------ */
145 /**
146 * Return the length of the resource
147 */
148 @Override
149 public long length()
150 {
151 if (checkConnection())
152 return _connection.getContentLength();
153 return -1;
154 }
155
156 /* ------------------------------------------------------------ */
157 /**
158 * Returns an URL representing the given resource
159 */
160 @Override
161 public URL getURL()
162 {
163 return _url;
164 }
165
166 /* ------------------------------------------------------------ */
167 /**
168 * Returns an File representing the given resource or NULL if this
169 * is not possible.
170 */
171 @Override
172 public File getFile()
173 throws IOException
174 {
175 // Try the permission hack
176 if (checkConnection())
177 {
178 Permission perm = _connection.getPermission();
179 if (perm instanceof java.io.FilePermission)
180 return new File(perm.getName());
181 }
182
183 // Try the URL file arg
184 try {return new File(_url.getFile());}
185 catch(Exception e) {LOG.ignore(e);}
186
187 // Don't know the file
188 return null;
189 }
190
191 /* ------------------------------------------------------------ */
192 /**
193 * Returns the name of the resource
194 */
195 @Override
196 public String getName()
197 {
198 return _url.toExternalForm();
199 }
200
201 /* ------------------------------------------------------------ */
202 /**
203 * Returns an input stream to the resource
204 */
205 @Override
206 public synchronized InputStream getInputStream()
207 throws java.io.IOException
208 {
209 if (!checkConnection())
210 throw new IOException( "Invalid resource");
211
212 try
213 {
214 if( _in != null)
215 {
216 InputStream in = _in;
217 _in=null;
218 return in;
219 }
220 return _connection.getInputStream();
221 }
222 finally
223 {
224 _connection=null;
225 }
226 }
227
228 /* ------------------------------------------------------------ */
229 @Override
230 public ReadableByteChannel getReadableByteChannel() throws IOException
231 {
232 return null;
233 }
234
235 /* ------------------------------------------------------------ */
236 /**
237 * Returns an output stream to the resource
238 */
239 @Override
240 public OutputStream getOutputStream()
241 throws java.io.IOException, SecurityException
242 {
243 throw new IOException( "Output not supported");
244 }
245
246 /* ------------------------------------------------------------ */
247 /**
248 * Deletes the given resource
249 */
250 @Override
251 public boolean delete()
252 throws SecurityException
253 {
254 throw new SecurityException( "Delete not supported");
255 }
256
257 /* ------------------------------------------------------------ */
258 /**
259 * Rename the given resource
260 */
261 @Override
262 public boolean renameTo( Resource dest)
263 throws SecurityException
264 {
265 throw new SecurityException( "RenameTo not supported");
266 }
267
268 /* ------------------------------------------------------------ */
269 /**
270 * Returns a list of resource names contained in the given resource
271 */
272 @Override
273 public String[] list()
274 {
275 return null;
276 }
277
278 /* ------------------------------------------------------------ */
279 /**
280 * Returns the resource contained inside the current resource with the
281 * given name
282 */
283 @Override
284 public Resource addPath(String path)
285 throws IOException,MalformedURLException
286 {
287 if (path==null)
288 return null;
289
290 path = URIUtil.canonicalPath(path);
291
292 return newResource(URIUtil.addPaths(_url.toExternalForm(),path));
293 }
294
295 /* ------------------------------------------------------------ */
296 @Override
297 public String toString()
298 {
299 return _urlString;
300 }
301
302 /* ------------------------------------------------------------ */
303 @Override
304 public int hashCode()
305 {
306 return _urlString.hashCode();
307 }
308
309 /* ------------------------------------------------------------ */
310 @Override
311 public boolean equals( Object o)
312 {
313 return o instanceof URLResource && _urlString.equals(((URLResource)o)._urlString);
314 }
315
316 /* ------------------------------------------------------------ */
317 public boolean getUseCaches ()
318 {
319 return _useCaches;
320 }
321
322 /* ------------------------------------------------------------ */
323 @Override
324 public boolean isContainedIn (Resource containingResource) throws MalformedURLException
325 {
326 return false;
327 }
328 }