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