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