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.
9 // The Eclipse Public License is available at
10 // http://www.eclipse.org/legal/epl-v10.html
12 // The Apache License v2.0 is available at
13 // http://www.opensource.org/licenses/apache2.0.php
15 // You may elect to redistribute this code under either of these licenses.
16 // ========================================================================
19 package org.eclipse.jetty.util.resource;
22 import java.io.IOException;
23 import java.io.InputStream;
24 import java.net.MalformedURLException;
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;
33 import org.eclipse.jetty.util.URIUtil;
34 import org.eclipse.jetty.util.log.Log;
35 import org.eclipse.jetty.util.log.Logger;
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.
47 public class ResourceCollection extends Resource
49 private static final Logger LOG = Log.getLogger(ResourceCollection.class);
50 private Resource[] _resources;
52 /* ------------------------------------------------------------ */
54 * Instantiates an empty resource collection.
56 * This constructor is used when configuring jetty-maven-plugin.
58 public ResourceCollection()
60 _resources = new Resource[0];
63 /* ------------------------------------------------------------ */
65 * Instantiates a new resource collection.
67 * @param resources the resources to be added to collection
69 public ResourceCollection(Resource... resources)
71 List<Resource> list = new ArrayList<Resource>();
72 for (Resource r : resources)
76 if (r instanceof ResourceCollection)
78 for (Resource r2 : ((ResourceCollection)r).getResources())
84 _resources = list.toArray(new Resource[list.size()]);
85 for(Resource r : _resources)
87 if(!r.exists() || !r.isDirectory())
88 throw new IllegalArgumentException(r + " is not an existing directory.");
93 /* ------------------------------------------------------------ */
95 * Instantiates a new resource collection.
97 * @param resources the resource strings to be added to collection
99 public ResourceCollection(String[] resources)
101 _resources = new Resource[resources.length];
104 for(int i=0; i<resources.length; i++)
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.");
111 catch(IllegalArgumentException e)
117 throw new RuntimeException(e);
121 /* ------------------------------------------------------------ */
123 * Instantiates a new resource collection.
125 * @param csvResources the string containing comma-separated resource strings
127 public ResourceCollection(String csvResources)
129 setResourcesAsCSV(csvResources);
132 /* ------------------------------------------------------------ */
134 * Retrieves the resource collection's resources.
136 * @return the resource array
138 public Resource[] getResources()
143 /* ------------------------------------------------------------ */
145 * Sets the resource collection's resources.
147 * @param resources the new resource array
149 public void setResources(Resource[] resources)
151 _resources = resources != null ? resources : new Resource[0];
154 /* ------------------------------------------------------------ */
156 * Sets the resources as string of comma-separated values.
157 * This method should be used when configuring jetty-maven-plugin.
159 * @param csvResources the comma-separated string containing
160 * one or more resource strings.
162 public void setResourcesAsCSV(String csvResources)
164 StringTokenizer tokenizer = new StringTokenizer(csvResources, ",;");
165 int len = tokenizer.countTokens();
168 throw new IllegalArgumentException("ResourceCollection@setResourcesAsCSV(String) " +
169 " argument must be a string containing one or more comma-separated resource strings.");
172 List<Resource> resources = new ArrayList<>();
176 while(tokenizer.hasMoreTokens())
178 Resource resource = Resource.newResource(tokenizer.nextToken().trim());
179 if(!resource.exists() || !resource.isDirectory())
180 LOG.warn(" !exist "+resource);
182 resources.add(resource);
187 throw new RuntimeException(e);
190 _resources = resources.toArray(new Resource[resources.size()]);
193 /* ------------------------------------------------------------ */
195 * @param path The path segment to add
196 * @return The contained resource (found first) in the collection of resources
199 public Resource addPath(String path) throws IOException, MalformedURLException
202 throw new IllegalStateException("*resources* not set.");
205 throw new MalformedURLException();
207 if(path.length()==0 || URIUtil.SLASH.equals(path))
210 Resource resource=null;
211 ArrayList<Resource> resources = null;
213 for(; i<_resources.length; i++)
215 resource = _resources[i].addPath(path);
216 if (resource.exists())
218 if (resource.isDirectory())
224 for(i++; i<_resources.length; i++)
226 Resource r = _resources[i].addPath(path);
227 if (r.exists() && r.isDirectory())
230 resources = new ArrayList<Resource>();
234 resources.add(resource);
245 return new ResourceCollection(resources.toArray(new Resource[resources.size()]));
249 /* ------------------------------------------------------------ */
252 * @return the resource(file) if found, returns a list of resource dirs if its a dir, else null.
253 * @throws IOException
254 * @throws MalformedURLException
256 protected Object findResource(String path) throws IOException, MalformedURLException
258 Resource resource=null;
259 ArrayList<Resource> resources = null;
261 for(; i<_resources.length; i++)
263 resource = _resources[i].addPath(path);
264 if (resource.exists())
266 if (resource.isDirectory())
273 for(i++; i<_resources.length; i++)
275 Resource r = _resources[i].addPath(path);
276 if (r.exists() && r.isDirectory())
280 resources = new ArrayList<Resource>();
281 resources.add(resource);
294 /* ------------------------------------------------------------ */
296 public boolean delete() throws SecurityException
298 throw new UnsupportedOperationException();
301 /* ------------------------------------------------------------ */
303 public boolean exists()
306 throw new IllegalStateException("*resources* not set.");
311 /* ------------------------------------------------------------ */
313 public File getFile() throws IOException
316 throw new IllegalStateException("*resources* not set.");
318 for(Resource r : _resources)
320 File f = r.getFile();
327 /* ------------------------------------------------------------ */
329 public InputStream getInputStream() throws IOException
332 throw new IllegalStateException("*resources* not set.");
334 for(Resource r : _resources)
336 InputStream is = r.getInputStream();
343 /* ------------------------------------------------------------ */
345 public ReadableByteChannel getReadableByteChannel() throws IOException
348 throw new IllegalStateException("*resources* not set.");
350 for(Resource r : _resources)
352 ReadableByteChannel channel = r.getReadableByteChannel();
359 /* ------------------------------------------------------------ */
361 public String getName()
364 throw new IllegalStateException("*resources* not set.");
366 for(Resource r : _resources)
368 String name = r.getName();
375 /* ------------------------------------------------------------ */
380 throw new IllegalStateException("*resources* not set.");
382 for(Resource r : _resources)
384 URL url = r.getURL();
391 /* ------------------------------------------------------------ */
393 public boolean isDirectory()
396 throw new IllegalStateException("*resources* not set.");
401 /* ------------------------------------------------------------ */
403 public long lastModified()
406 throw new IllegalStateException("*resources* not set.");
408 for(Resource r : _resources)
410 long lm = r.lastModified();
417 /* ------------------------------------------------------------ */
424 /* ------------------------------------------------------------ */
426 * @return The list of resource names(merged) contained in the collection of resources.
429 public String[] list()
432 throw new IllegalStateException("*resources* not set.");
434 HashSet<String> set = new HashSet<String>();
435 for(Resource r : _resources)
437 for(String s : r.list())
440 String[] result=set.toArray(new String[set.size()]);
445 /* ------------------------------------------------------------ */
450 throw new IllegalStateException("*resources* not set.");
452 for(Resource r : _resources)
456 /* ------------------------------------------------------------ */
458 public boolean renameTo(Resource dest) throws SecurityException
460 throw new UnsupportedOperationException();
463 /* ------------------------------------------------------------ */
465 public void copyTo(File destination)
468 for (int r=_resources.length;r-->0;)
469 _resources[r].copyTo(destination);
472 /* ------------------------------------------------------------ */
474 * @return the list of resources separated by a path separator
477 public String toString()
482 return String.valueOf(Arrays.asList(_resources));
485 /* ------------------------------------------------------------ */
487 public boolean isContainedIn(Resource r) throws MalformedURLException
489 // TODO could look at implementing the semantic of is this collection a subset of the Resource r?