1
2
3
4
5
6
7
8
9
10
11
12
13
14 package org.mortbay.resource;
15
16 import java.io.File;
17 import java.io.IOException;
18 import java.io.InputStream;
19 import java.io.OutputStream;
20 import java.io.Serializable;
21 import java.net.MalformedURLException;
22 import java.net.URL;
23 import java.net.URLConnection;
24 import java.text.DateFormat;
25 import java.util.Arrays;
26 import java.util.Date;
27
28 import org.mortbay.log.Log;
29 import org.mortbay.util.IO;
30 import org.mortbay.util.Loader;
31 import org.mortbay.util.StringUtil;
32 import org.mortbay.util.URIUtil;
33 import org.mortbay.util.UrlEncoded;
34
35
36
37
38
39
40
41
42 public abstract class Resource implements Serializable
43 {
44 public static boolean __defaultUseCaches = true;
45 Object _associate;
46
47
48
49
50
51
52 public static void setDefaultUseCaches (boolean useCaches)
53 {
54 __defaultUseCaches=useCaches;
55 }
56
57 public static boolean getDefaultUseCaches ()
58 {
59 return __defaultUseCaches;
60 }
61
62
63
64
65
66
67 public static Resource newResource(URL url)
68 throws IOException
69 {
70 return newResource(url, __defaultUseCaches);
71 }
72
73
74
75
76
77
78
79
80 public static Resource newResource(URL url, boolean useCaches)
81 {
82 if (url==null)
83 return null;
84
85 String url_string=url.toExternalForm();
86 if( url_string.startsWith( "file:"))
87 {
88 try
89 {
90 FileResource fileResource= new FileResource(url);
91 return fileResource;
92 }
93 catch(Exception e)
94 {
95 Log.debug(Log.EXCEPTION,e);
96 return new BadResource(url,e.toString());
97 }
98 }
99 else if( url_string.startsWith( "jar:file:"))
100 {
101 return new JarFileResource(url, useCaches);
102 }
103 else if( url_string.startsWith( "jar:"))
104 {
105 return new JarResource(url, useCaches);
106 }
107
108 return new URLResource(url,null,useCaches);
109 }
110
111
112
113
114
115
116
117
118 public static Resource newResource(String resource)
119 throws MalformedURLException, IOException
120 {
121 return newResource(resource, __defaultUseCaches);
122 }
123
124
125
126
127
128
129
130 public static Resource newResource (String resource, boolean useCaches)
131 throws MalformedURLException, IOException
132 {
133 URL url=null;
134 try
135 {
136
137 url = new URL(resource);
138 }
139 catch(MalformedURLException e)
140 {
141 if(!resource.startsWith("ftp:") &&
142 !resource.startsWith("file:") &&
143 !resource.startsWith("jar:"))
144 {
145 try
146 {
147
148 if (resource.startsWith("./"))
149 resource=resource.substring(2);
150
151 File file=new File(resource).getCanonicalFile();
152 url=new URL(URIUtil.encodePath(file.toURL().toString()));
153
154 URLConnection connection=url.openConnection();
155 connection.setUseCaches(useCaches);
156 FileResource fileResource= new FileResource(url,connection,file);
157 return fileResource;
158 }
159 catch(Exception e2)
160 {
161 Log.debug(Log.EXCEPTION,e2);
162 throw e;
163 }
164 }
165 else
166 {
167 Log.warn("Bad Resource: "+resource);
168 throw e;
169 }
170 }
171
172
173 String nurl=url.toString();
174 if (nurl.length()>0 && nurl.charAt(nurl.length()-1)!=resource.charAt(resource.length()-1))
175 {
176 if ((nurl.charAt(nurl.length()-1)!='/' ||
177 nurl.charAt(nurl.length()-2)!=resource.charAt(resource.length()-1))
178 &&
179 (resource.charAt(resource.length()-1)!='/' ||
180 resource.charAt(resource.length()-2)!=nurl.charAt(nurl.length()-1)
181 ))
182 {
183 return new BadResource(url,"Trailing special characters stripped by URL in "+resource);
184 }
185 }
186 return newResource(url);
187 }
188
189
190
191
192
193
194 public static Resource newSystemResource(String resource)
195 throws IOException
196 {
197 URL url=null;
198
199 ClassLoader
200 loader=Thread.currentThread().getContextClassLoader();
201 if (loader!=null)
202 {
203 url=loader.getResource(resource);
204 if (url==null && resource.startsWith("/"))
205 url=loader.getResource(resource.substring(1));
206 }
207 if (url==null)
208 {
209 loader=Resource.class.getClassLoader();
210 if (loader!=null)
211 {
212 url=loader.getResource(resource);
213 if (url==null && resource.startsWith("/"))
214 url=loader.getResource(resource.substring(1));
215 }
216 }
217
218 if (url==null)
219 {
220 url=ClassLoader.getSystemResource(resource);
221 if (url==null && resource.startsWith("/"))
222 url=loader.getResource(resource.substring(1));
223 }
224
225 if (url==null)
226 return null;
227
228 return newResource(url);
229 }
230
231
232
233
234 public static Resource newClassPathResource(String resource)
235 {
236 return newClassPathResource(resource,true,false);
237 }
238
239
240
241
242
243
244
245
246
247
248
249
250
251 public static Resource newClassPathResource(String name,boolean useCaches,boolean checkParents)
252 {
253 URL url=Resource.class.getResource(name);
254
255 if (url==null)
256 {
257 try
258 {
259 url=Loader.getResource(Resource.class,name,checkParents);
260 }
261 catch(ClassNotFoundException e)
262 {
263 url=ClassLoader.getSystemResource(name);
264 }
265 }
266 if (url==null)
267 return null;
268 return newResource(url,useCaches);
269 }
270
271
272
273
274 protected void finalize()
275 {
276 release();
277 }
278
279
280
281
282 public abstract void release();
283
284
285
286
287
288
289 public abstract boolean exists();
290
291
292
293
294
295
296
297
298 public abstract boolean isDirectory();
299
300
301
302
303
304 public abstract long lastModified();
305
306
307
308
309
310
311 public abstract long length();
312
313
314
315
316
317
318 public abstract URL getURL();
319
320
321
322
323
324
325
326 public abstract File getFile()
327 throws IOException;
328
329
330
331
332
333
334 public abstract String getName();
335
336
337
338
339
340
341 public abstract InputStream getInputStream()
342 throws java.io.IOException;
343
344
345
346
347
348 public abstract OutputStream getOutputStream()
349 throws java.io.IOException, SecurityException;
350
351
352
353
354
355 public abstract boolean delete()
356 throws SecurityException;
357
358
359
360
361
362 public abstract boolean renameTo( Resource dest)
363 throws SecurityException;
364
365
366
367
368
369
370 public abstract String[] list();
371
372
373
374
375
376
377
378
379 public abstract Resource addPath(String path)
380 throws IOException,MalformedURLException;
381
382
383
384
385
386
387
388
389 public String encode(String uri)
390 {
391 return URIUtil.encodePath(uri);
392 }
393
394
395 public Object getAssociate()
396 {
397 return _associate;
398 }
399
400
401 public void setAssociate(Object o)
402 {
403 _associate=o;
404 }
405
406
407
408
409
410 public URL getAlias()
411 {
412 return null;
413 }
414
415
416
417
418
419
420
421 public String getListHTML(String base,boolean parent)
422 throws IOException
423 {
424 base=URIUtil.canonicalPath(base);
425 if (base==null || !isDirectory())
426 return null;
427
428 String[] ls = list();
429 if (ls==null)
430 return null;
431 Arrays.sort(ls);
432
433 String decodedBase = URIUtil.decodePath(base);
434 String title = "Directory: "+deTag(decodedBase);
435
436 StringBuffer buf=new StringBuffer(4096);
437 buf.append("<HTML><HEAD><TITLE>");
438 buf.append(title);
439 buf.append("</TITLE></HEAD><BODY>\n<H1>");
440 buf.append(title);
441 buf.append("</H1>\n<TABLE BORDER=0>\n");
442
443 if (parent)
444 {
445 buf.append("<TR><TD><A HREF=\"");
446 buf.append(URIUtil.addPaths(base,"../"));
447 buf.append("\">Parent Directory</A></TD><TD></TD><TD></TD></TR>\n");
448 }
449
450 String defangedBase = defangURI(base);
451
452 DateFormat dfmt=DateFormat.getDateTimeInstance(DateFormat.MEDIUM,
453 DateFormat.MEDIUM);
454 for (int i=0 ; i< ls.length ; i++)
455 {
456 Resource item = addPath(ls[i]);
457
458 buf.append("\n<TR><TD><A HREF=\"");
459 String path=URIUtil.addPaths(defangedBase,URIUtil.encodePath(ls[i]));
460
461 buf.append(path);
462
463 if (item.isDirectory() && !path.endsWith("/"))
464 buf.append(URIUtil.SLASH);
465
466
467 buf.append("\">");
468 buf.append(deTag(ls[i]));
469 buf.append(" ");
470 buf.append("</TD><TD ALIGN=right>");
471 buf.append(item.length());
472 buf.append(" bytes </TD><TD>");
473 buf.append(dfmt.format(new Date(item.lastModified())));
474 buf.append("</TD></TR>");
475 }
476 buf.append("</TABLE>\n");
477 buf.append("</BODY></HTML>\n");
478
479 return buf.toString();
480 }
481
482
483
484
485
486
487
488
489
490
491
492 private static String defangURI(String raw)
493 {
494 StringBuffer buf = null;
495
496 if (buf==null)
497 {
498 for (int i=0;i<raw.length();i++)
499 {
500 char c=raw.charAt(i);
501 switch(c)
502 {
503 case '\'':
504 case '"':
505 case '<':
506 case '>':
507 buf=new StringBuffer(raw.length()<<1);
508 break;
509 }
510 }
511 if (buf==null)
512 return raw;
513 }
514
515 for (int i=0;i<raw.length();i++)
516 {
517 char c=raw.charAt(i);
518 switch(c)
519 {
520 case '"':
521 buf.append("%22");
522 continue;
523 case '\'':
524 buf.append("%27");
525 continue;
526 case '<':
527 buf.append("%3C");
528 continue;
529 case '>':
530 buf.append("%3E");
531 continue;
532 default:
533 buf.append(c);
534 continue;
535 }
536 }
537
538 return buf.toString();
539 }
540
541 private static String deTag(String raw)
542 {
543 return StringUtil.replace( StringUtil.replace(raw,"<","<"), ">", ">");
544 }
545
546
547
548
549
550
551
552 public void writeTo(OutputStream out,long start,long count)
553 throws IOException
554 {
555 InputStream in = getInputStream();
556 try
557 {
558 in.skip(start);
559 if (count<0)
560 IO.copy(in,out);
561 else
562 IO.copy(in,out,count);
563 }
564 finally
565 {
566 in.close();
567 }
568 }
569 }