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