View Javadoc

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.nio.channels.ReadableByteChannel;
28  import java.util.ArrayList;
29  import java.util.Arrays;
30  import java.util.HashSet;
31  import java.util.List;
32  import java.util.StringTokenizer;
33  
34  import org.eclipse.jetty.util.URIUtil;
35  
36  /**
37   * A collection of resources (dirs).
38   * Allows webapps to have multiple (static) sources.
39   * The first resource in the collection is the main resource.
40   * If a resource is not found in the main resource, it looks it up in 
41   * the order the resources were constructed.
42   * 
43   * 
44   *
45   */
46  public class ResourceCollection extends Resource
47  {
48      private Resource[] _resources;
49  
50      /* ------------------------------------------------------------ */
51      /**
52       * Instantiates an empty resource collection.
53       * 
54       * This constructor is used when configuring jetty-maven-plugin.
55       */
56      public ResourceCollection()
57      {
58          _resources = new Resource[0];
59      }
60      
61      /* ------------------------------------------------------------ */
62      /**
63       * Instantiates a new resource collection.
64       *
65       * @param resources the resources to be added to collection
66       */
67      public ResourceCollection(Resource... resources)
68      {
69          List<Resource> list = new ArrayList<Resource>();
70          for (Resource r : resources)
71          {
72              if (r==null)
73                  continue;
74              if (r instanceof ResourceCollection)
75              {
76                  for (Resource r2 : ((ResourceCollection)r).getResources())
77                      list.add(r2);
78              }
79              else
80                  list.add(r);
81          }
82          _resources = list.toArray(new Resource[list.size()]);
83          for(Resource r : _resources)
84          {
85              if(!r.exists() || !r.isDirectory())
86                  throw new IllegalArgumentException(r + " is not an existing directory.");
87          }
88      }
89      
90      
91      /* ------------------------------------------------------------ */
92      /**
93       * Instantiates a new resource collection.
94       *
95       * @param resources the resource strings to be added to collection
96       */
97      public ResourceCollection(String[] resources)
98      {
99          _resources = new Resource[resources.length];
100         try
101         {
102             for(int i=0; i<resources.length; i++)
103             {
104                 _resources[i] = Resource.newResource(resources[i]);
105                 if(!_resources[i].exists() || !_resources[i].isDirectory())
106                     throw new IllegalArgumentException(_resources[i] + " is not an existing directory.");
107             }
108         }
109         catch(IllegalArgumentException e)
110         {
111             throw e;
112         }
113         catch(Exception e)
114         {
115             throw new RuntimeException(e);
116         }
117     }
118     
119     /* ------------------------------------------------------------ */
120     /**
121      * Instantiates a new resource collection.
122      *
123      * @param csvResources the string containing comma-separated resource strings
124      */
125     public ResourceCollection(String csvResources)
126     {
127         setResourcesAsCSV(csvResources);
128     }
129     
130     /* ------------------------------------------------------------ */
131     /**
132      * Retrieves the resource collection's resources.
133      * 
134      * @return the resource array
135      */
136     public Resource[] getResources()
137     {
138         return _resources;
139     }
140     
141     /* ------------------------------------------------------------ */
142     /**
143      * Sets the resource collection's resources.
144      *
145      * @param resources the new resource array
146      */
147     public void setResources(Resource[] resources)
148     {
149         _resources = resources != null ? resources : new Resource[0];
150     }
151 
152     /* ------------------------------------------------------------ */
153     /**
154      * Sets the resources as string of comma-separated values.
155      * This method should be used when configuring jetty-maven-plugin.
156      *
157      * @param csvResources the comma-separated string containing
158      *                     one or more resource strings.
159      */
160     public void setResourcesAsCSV(String csvResources)
161     {
162         StringTokenizer tokenizer = new StringTokenizer(csvResources, ",;");
163         int len = tokenizer.countTokens();
164         if(len==0)
165         {
166             throw new IllegalArgumentException("ResourceCollection@setResourcesAsCSV(String) " +
167                     " argument must be a string containing one or more comma-separated resource strings.");
168         }
169         
170         _resources = new Resource[len];
171         try
172         {            
173             for(int i=0; tokenizer.hasMoreTokens(); i++)
174             {
175                 _resources[i] = Resource.newResource(tokenizer.nextToken().trim());
176                 if(!_resources[i].exists() || !_resources[i].isDirectory())
177                     throw new IllegalArgumentException(_resources[i] + " is not an existing directory.");
178             }
179         }
180         catch(Exception e)
181         {
182             throw new RuntimeException(e);
183         }
184     }
185     
186     /* ------------------------------------------------------------ */
187     /**
188      * @param path The path segment to add
189      * @return The contained resource (found first) in the collection of resources
190      */
191     @Override
192     public Resource addPath(String path) throws IOException, MalformedURLException
193     {
194         if(_resources==null)
195             throw new IllegalStateException("*resources* not set.");
196         
197         if(path==null)
198             throw new MalformedURLException();
199         
200         if(path.length()==0 || URIUtil.SLASH.equals(path))
201             return this;
202         
203         Resource resource=null;
204         ArrayList<Resource> resources = null;
205         int i=0;
206         for(; i<_resources.length; i++)
207         {
208             resource = _resources[i].addPath(path);  
209             if (resource.exists())
210             {
211                 if (resource.isDirectory())
212                     break;       
213                 return resource;
214             }
215         }  
216 
217         for(i++; i<_resources.length; i++)
218         {
219             Resource r = _resources[i].addPath(path); 
220             if (r.exists() && r.isDirectory())
221             {
222                 if (resource!=null)
223                 {
224                     resources = new ArrayList<Resource>();
225                     resources.add(resource);
226                     resource=null;
227                 }
228                 resources.add(r);
229             }
230         }
231 
232         if (resource!=null)
233             return resource;
234         if (resources!=null)
235             return new ResourceCollection(resources.toArray(new Resource[resources.size()]));
236         return null;
237     }
238     
239     /* ------------------------------------------------------------ */
240     /**
241      * @param path
242      * @return the resource(file) if found, returns a list of resource dirs if its a dir, else null.
243      * @throws IOException
244      * @throws MalformedURLException
245      */
246     protected Object findResource(String path) throws IOException, MalformedURLException
247     {        
248         Resource resource=null;
249         ArrayList<Resource> resources = null;
250         int i=0;
251         for(; i<_resources.length; i++)
252         {
253             resource = _resources[i].addPath(path);  
254             if (resource.exists())
255             {
256                 if (resource.isDirectory())
257                     break;
258                
259                 return resource;
260             }
261         }  
262 
263         for(i++; i<_resources.length; i++)
264         {
265             Resource r = _resources[i].addPath(path); 
266             if (r.exists() && r.isDirectory())
267             {
268                 if (resource!=null)
269                 {
270                     resources = new ArrayList<Resource>();
271                     resources.add(resource);
272                 }
273                 resources.add(r);
274             }
275         }
276         
277         if (resource!=null)
278             return resource;
279         if (resources!=null)
280             return resources;
281         return null;
282     }
283     
284     /* ------------------------------------------------------------ */
285     @Override
286     public boolean delete() throws SecurityException
287     {
288         throw new UnsupportedOperationException();
289     }
290     
291     /* ------------------------------------------------------------ */
292     @Override
293     public boolean exists()
294     {
295         if(_resources==null)
296             throw new IllegalStateException("*resources* not set.");
297         
298         return true;
299     }
300     
301     /* ------------------------------------------------------------ */
302     @Override
303     public File getFile() throws IOException
304     {
305         if(_resources==null)
306             throw new IllegalStateException("*resources* not set.");
307         
308         for(Resource r : _resources)
309         {
310             File f = r.getFile();
311             if(f!=null)
312                 return f;
313         }
314         return null;
315     }
316     
317     /* ------------------------------------------------------------ */
318     @Override
319     public InputStream getInputStream() throws IOException
320     {
321         if(_resources==null)
322             throw new IllegalStateException("*resources* not set.");
323         
324         for(Resource r : _resources)
325         {
326             InputStream is = r.getInputStream();
327             if(is!=null)
328                 return is;
329         }
330         return null;
331     }
332 
333     /* ------------------------------------------------------------ */
334     @Override 
335     public ReadableByteChannel getReadableByteChannel() throws IOException
336     {
337         if(_resources==null)
338             throw new IllegalStateException("*resources* not set.");
339         
340         for(Resource r : _resources)
341         {
342             ReadableByteChannel channel = r.getReadableByteChannel();
343             if(channel!=null)
344                 return channel;
345         }
346         return null;
347     }
348     
349     /* ------------------------------------------------------------ */
350     @Override
351     public String getName()
352     {
353         if(_resources==null)
354             throw new IllegalStateException("*resources* not set.");
355         
356         for(Resource r : _resources)
357         {
358             String name = r.getName();
359             if(name!=null)
360                 return name;
361         }
362         return null;
363     }
364     
365     /* ------------------------------------------------------------ */
366     @Override
367     public OutputStream getOutputStream() throws IOException, SecurityException
368     {
369         if(_resources==null)
370             throw new IllegalStateException("*resources* not set.");
371         
372         for(Resource r : _resources)
373         {
374             OutputStream os = r.getOutputStream();
375             if(os!=null)
376                 return os;
377         }
378         return null;
379     }
380     
381     /* ------------------------------------------------------------ */
382     @Override
383     public URL getURL()
384     {
385         if(_resources==null)
386             throw new IllegalStateException("*resources* not set.");
387         
388         for(Resource r : _resources)
389         {
390             URL url = r.getURL();
391             if(url!=null)
392                 return url;
393         }
394         return null;
395     }
396     
397     /* ------------------------------------------------------------ */
398     @Override
399     public boolean isDirectory()
400     {
401         if(_resources==null)
402             throw new IllegalStateException("*resources* not set.");
403         
404         return true;
405     }
406     
407     /* ------------------------------------------------------------ */
408     @Override
409     public long lastModified()
410     {
411         if(_resources==null)
412             throw new IllegalStateException("*resources* not set.");
413         
414         for(Resource r : _resources)
415         {
416             long lm = r.lastModified();
417             if (lm!=-1)
418                 return lm;
419         }
420         return -1;
421     }
422     
423     /* ------------------------------------------------------------ */
424     @Override
425     public long length()
426     {
427         return -1;
428     }    
429     
430     /* ------------------------------------------------------------ */
431     /**
432      * @return The list of resource names(merged) contained in the collection of resources.
433      */    
434     @Override
435     public String[] list()
436     {
437         if(_resources==null)
438             throw new IllegalStateException("*resources* not set.");
439         
440         HashSet<String> set = new HashSet<String>();
441         for(Resource r : _resources)
442         {
443             for(String s : r.list())
444                 set.add(s);
445         }
446         String[] result=set.toArray(new String[set.size()]);
447         Arrays.sort(result);
448         return result;
449     }
450     
451     /* ------------------------------------------------------------ */
452     @Override
453     public void release()
454     {
455         if(_resources==null)
456             throw new IllegalStateException("*resources* not set.");
457         
458         for(Resource r : _resources)
459             r.release();
460     }
461     
462     /* ------------------------------------------------------------ */
463     @Override
464     public boolean renameTo(Resource dest) throws SecurityException
465     {
466         throw new UnsupportedOperationException();
467     }
468 
469     /* ------------------------------------------------------------ */
470     @Override
471     public void copyTo(File destination)
472         throws IOException
473     {
474         for (int r=_resources.length;r-->0;)
475             _resources[r].copyTo(destination);
476     }
477     
478     /* ------------------------------------------------------------ */
479     /**
480      * @return the list of resources separated by a path separator
481      */
482     @Override
483     public String toString()
484     {
485         if(_resources==null)
486             return "[]";
487         
488         return String.valueOf(Arrays.asList(_resources));
489     }
490 
491     /* ------------------------------------------------------------ */
492     @Override
493     public boolean isContainedIn(Resource r) throws MalformedURLException
494     {
495         // TODO could look at implementing the semantic of is this collection a subset of the Resource r?
496         return false;
497     }
498 
499 }