//
// ========================================================================
// Copyright (c) 1995-2020 Mort Bay Consulting Pty Ltd and others.
//
// This program and the accompanying materials are made available under
// the terms of the Eclipse Public License 2.0 which is available at
// https://www.eclipse.org/legal/epl-2.0
//
// This Source Code may also be made available under the following
// Secondary Licenses when the conditions for such availability set
// forth in the Eclipse Public License, v. 2.0 are satisfied:
// the Apache License v2.0 which is available at
// https://www.apache.org/licenses/LICENSE-2.0
//
// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
// ========================================================================
//

package org.eclipse.jetty.util.resource;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URI;
import java.nio.channels.ReadableByteChannel;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;

import org.eclipse.jetty.util.StringUtil;
import org.eclipse.jetty.util.URIUtil;

A collection of resources (dirs). Allows webapps to have multiple (static) sources. The first resource in the collection is the main resource. If a resource is not found in the main resource, it looks it up in the order the resources were constructed.
/** * A collection of resources (dirs). * Allows webapps to have multiple (static) sources. * The first resource in the collection is the main resource. * If a resource is not found in the main resource, it looks it up in * the order the resources were constructed. */
public class ResourceCollection extends Resource { private List<Resource> _resources;
Instantiates an empty resource collection.

This constructor is used when configuring jetty-maven-plugin.

/** * Instantiates an empty resource collection. * <p> * This constructor is used when configuring jetty-maven-plugin. */
public ResourceCollection() { _resources = new ArrayList<>(); }
Instantiates a new resource collection.
Params:
  • resources – the resources to be added to collection
/** * Instantiates a new resource collection. * * @param resources the resources to be added to collection */
public ResourceCollection(Resource... resources) { this(Arrays.asList(resources)); }
Instantiates a new resource collection.
Params:
  • resources – the resources to be added to collection
/** * Instantiates a new resource collection. * * @param resources the resources to be added to collection */
public ResourceCollection(Collection<Resource> resources) { _resources = new ArrayList<>(); for (Resource r : resources) { if (r == null) { continue; } if (r instanceof ResourceCollection) { _resources.addAll(((ResourceCollection)r).getResources()); } else { assertResourceValid(r); _resources.add(r); } } }
Instantiates a new resource collection.
Params:
  • resources – the resource strings to be added to collection
/** * Instantiates a new resource collection. * * @param resources the resource strings to be added to collection */
public ResourceCollection(String[] resources) { _resources = new ArrayList<>(); if (resources == null || resources.length == 0) { return; } try { for (String strResource : resources) { if (strResource == null || strResource.length() == 0) { throw new IllegalArgumentException("empty/null resource path not supported"); } Resource resource = Resource.newResource(strResource); assertResourceValid(resource); _resources.add(resource); } if (_resources.isEmpty()) { throw new IllegalArgumentException("resources cannot be empty or null"); } } catch (RuntimeException e) { throw e; } catch (Exception e) { throw new RuntimeException(e); } }
Instantiates a new resource collection.
Params:
  • csvResources – the string containing comma-separated resource strings
Throws:
/** * Instantiates a new resource collection. * * @param csvResources the string containing comma-separated resource strings * @throws IOException if any listed resource is not valid */
public ResourceCollection(String csvResources) throws IOException { setResources(csvResources); }
Retrieves the resource collection's resources.
Returns:the resource collection
/** * Retrieves the resource collection's resources. * * @return the resource collection */
public List<Resource> getResources() { return _resources; }
Sets the resource collection's resources.
Params:
  • res – the resources to set
/** * Sets the resource collection's resources. * * @param res the resources to set */
public void setResources(List<Resource> res) { _resources = new ArrayList<>(); if (res.isEmpty()) { return; } _resources.addAll(res); }
Sets the resource collection's resources.
Params:
  • resources – the new resource array
/** * Sets the resource collection's resources. * * @param resources the new resource array */
public void setResources(Resource[] resources) { if (resources == null || resources.length == 0) { _resources = null; return; } List<Resource> res = new ArrayList<>(); for (Resource resource : resources) { assertResourceValid(resource); res.add(resource); } setResources(res); }
Sets the resources as string of comma-separated values. This method should be used when configuring jetty-maven-plugin.
Params:
  • resources – the comma-separated string containing one or more resource strings.
Throws:
  • IOException – if unable resource declared is not valid
See Also:
/** * Sets the resources as string of comma-separated values. * This method should be used when configuring jetty-maven-plugin. * * @param resources the comma-separated string containing * one or more resource strings. * @throws IOException if unable resource declared is not valid * @see Resource#fromList(String, boolean) */
public void setResources(String resources) throws IOException { if (StringUtil.isBlank(resources)) { throw new IllegalArgumentException("String is blank"); } List<Resource> list = Resource.fromList(resources, false); if (list.isEmpty()) { throw new IllegalArgumentException("String contains no entries"); } List<Resource> ret = new ArrayList<>(); for (Resource resource : list) { assertResourceValid(resource); ret.add(resource); } setResources(ret); }
Add a path to the resource collection.
Params:
  • path – The path segment to add
Throws:
  • MalformedURLException – if the resolution of the path fails because the input path parameter is malformed against any of the collection
Returns:The resulting resource(s) :
  • is a file that exists in at least one of the collection, then the first one found is returned
  • is a directory that exists in at exactly one of the collection, then that directory resource is returned
  • is a directory that exists in several of the collection, then a ResourceCollection of those directories is returned
  • do not exist in any of the collection, then a new non existent resource relative to the first in the collection is returned.
/** * Add a path to the resource collection. * @param path The path segment to add * @return The resulting resource(s) : * <ul> * <li>is a file that exists in at least one of the collection, then the first one found is returned</li> * <li>is a directory that exists in at exactly one of the collection, then that directory resource is returned </li> * <li>is a directory that exists in several of the collection, then a ResourceCollection of those directories is returned</li> * <li>do not exist in any of the collection, then a new non existent resource relative to the first in the collection is returned.</li> * </ul> * @throws MalformedURLException if the resolution of the path fails because the input path parameter is malformed against any of the collection */
@Override public Resource addPath(String path) throws IOException { assertResourcesSet(); if (path == null) { throw new MalformedURLException("null path"); } if (path.length() == 0 || URIUtil.SLASH.equals(path)) { return this; } ArrayList<Resource> resources = null; // Attempt a simple (single) Resource lookup that exists Resource addedResource = null; for (Resource res : _resources) { addedResource = res.addPath(path); if (!addedResource.exists()) continue; if (!addedResource.isDirectory()) return addedResource; // Return simple (non-directory) Resource if (resources == null) resources = new ArrayList<>(); resources.add(addedResource); } if (resources == null) { if (addedResource != null) return addedResource; // This will not exist return EmptyResource.INSTANCE; } if (resources.size() == 1) return resources.get(0); return new ResourceCollection(resources); } @Override public boolean delete() throws SecurityException { throw new UnsupportedOperationException(); } @Override public boolean exists() { assertResourcesSet(); for (Resource r : _resources) { if (r.exists()) { return true; } } return false; } @Override public File getFile() throws IOException { assertResourcesSet(); for (Resource r : _resources) { File f = r.getFile(); if (f != null) { return f; } } return null; } @Override public InputStream getInputStream() throws IOException { assertResourcesSet(); for (Resource r : _resources) { if (!r.exists()) { // Skip, cannot open anyway continue; } InputStream is = r.getInputStream(); if (is != null) { return is; } } throw new FileNotFoundException("Resource does not exist"); } @Override public ReadableByteChannel getReadableByteChannel() throws IOException { assertResourcesSet(); for (Resource r : _resources) { ReadableByteChannel channel = r.getReadableByteChannel(); if (channel != null) { return channel; } } return null; } @Override public String getName() { assertResourcesSet(); for (Resource r : _resources) { String name = r.getName(); if (name != null) { return name; } } return null; } @Override public URI getURI() { assertResourcesSet(); for (Resource r : _resources) { URI uri = r.getURI(); if (uri != null) { return uri; } } return null; } @Override public boolean isDirectory() { assertResourcesSet(); return true; } @Override public long lastModified() { assertResourcesSet(); for (Resource r : _resources) { long lm = r.lastModified(); if (lm != -1) { return lm; } } return -1; } @Override public long length() { return -1; }
Returns:The list of resource names(merged) contained in the collection of resources.
/** * @return The list of resource names(merged) contained in the collection of resources. */
@Override public String[] list() { assertResourcesSet(); HashSet<String> set = new HashSet<>(); for (Resource r : _resources) { String[] list = r.list(); if (list != null) Collections.addAll(set, list); } String[] result = set.toArray(new String[0]); Arrays.sort(result); return result; } @Override public void close() { assertResourcesSet(); for (Resource r : _resources) { r.close(); } } @Override public boolean renameTo(Resource dest) throws SecurityException { throw new UnsupportedOperationException(); } @Override public void copyTo(File destination) throws IOException { assertResourcesSet(); // Copy in reverse order for (int r = _resources.size(); r-- > 0; ) { _resources.get(r).copyTo(destination); } }
Returns:the list of resources separated by a path separator
/** * @return the list of resources separated by a path separator */
@Override public String toString() { if (_resources.isEmpty()) { return "[]"; } return String.valueOf(_resources); } @Override public boolean isContainedIn(Resource r) { // TODO could look at implementing the semantic of is this collection a subset of the Resource r? return false; } private void assertResourcesSet() { if (_resources == null || _resources.isEmpty()) { throw new IllegalStateException("*resources* not set."); } } private void assertResourceValid(Resource resource) { if (resource == null) { throw new IllegalStateException("Null resource not supported"); } if (!resource.exists() || !resource.isDirectory()) { throw new IllegalArgumentException(resource + " is not an existing directory."); } } }